Merge "Adding additional prompt to UsbPermissionsDialg for audio devices."
diff --git a/Android.bp b/Android.bp
index 6fc233c..594126f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -112,6 +112,14 @@
 }
 
 filegroup {
+    name: "framework-mime-sources",
+    srcs: [
+        "mime/java/**/*.java",
+    ],
+    path: "mime/java",
+}
+
+filegroup {
     name: "framework-opengl-sources",
     srcs: [
         "opengl/java/**/*.java",
@@ -154,6 +162,14 @@
 }
 
 filegroup {
+    name: "framework-telephony-common-sources",
+    srcs: [
+        "telephony/common/**/*.java",
+    ],
+    path: "telephony/common",
+}
+
+filegroup {
     name: "framework-wifi-sources",
     srcs: [
         "wifi/java/**/*.java",
@@ -176,10 +192,12 @@
         ":framework-mca-effect-sources",
         ":framework-mca-filterfw-sources",
         ":framework-mca-filterpacks-sources",
+        ":framework-mime-sources",
         ":framework-opengl-sources",
         ":framework-rs-sources",
         ":framework-sax-sources",
         ":framework-telecomm-sources",
+        ":framework-telephony-common-sources",
         ":framework-telephony-sources",
         ":framework-wifi-sources",
         ":PacProcessor-aidl-sources",
@@ -316,7 +334,10 @@
 
     jarjar_rules: ":framework-jarjar-rules",
 
-    static_libs: ["framework-internal-utils"],
+    static_libs: [
+        "framework-internal-utils",
+        "mimemap",
+    ],
 
     dxflags: [
         "--core-library",
@@ -802,6 +823,7 @@
     "opengl/java",
     "sax/java",
     "telecomm/java",
+    "telephony/common",
     "telephony/java",
     "wifi/java",
     "lowpan/java",
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 6a909c0..f7a2858 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -254,6 +254,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DefaultContainerService)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/CaptivePortalLogin)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ext.jar)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/google/android/mms)
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
 # ******************************************************************
diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md
index c1ad666..ea20e3e 100644
--- a/apex/jobscheduler/README_js-mainline.md
+++ b/apex/jobscheduler/README_js-mainline.md
@@ -1,23 +1,11 @@
 # Making Job Scheduler into a Mainline Module
 
-## TODOs
-
-See also:
-- http://go/moving-js-code-for-mainline
-- http://go/jobscheduler-code-dependencies-2019-07
-
-- [ ] Move this into `frameworks/apex/jobscheduler/...`. Currently it's in `frameworks/base/apex/...`
-because `frameworks/apex/` is not a part of any git projects. (and also working on multiple
-projects is a pain.)
-
 ## Current structure
 
 - JS service side classes are put in `jobscheduler-service.jar`.
 It's *not* included in services.jar, and instead it's put in the system server classpath,
 which currently looks like the following:
-`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/jobscheduler-service.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar`
-
-  (Note `jobscheduler-service.jar` will be put at the end in http://ag/9128109)
+`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/jobscheduler-service.jar`
 
   `SYSTEMSERVERCLASSPATH` is generated from `PRODUCT_SYSTEM_SERVER_JARS`.
 
@@ -29,10 +17,4 @@
   `framework.jar` merging the two jar files, and this jar file is what's
   put on the device and loaded by Zygote.
 
-
-This is *not* the final design. From a gerrit comment on http://ag/9145619:
-
-> This CL is just the first step, and the current state isn't not really the final form. For now we just want to have two separate jars, which makes it easier for us to analyze dependencies between them, and I wanted to minimize the change to the rest of the system. So, for example, zygote will still only have "framework.jar" in its classpath, instead of the two jars for now.
-> But yes, eventually, we won't even be able to have the monolithic "framework.jar" file because of mainline, so we need to figure out how to build the system without creating it. At that point zygote will have the two separate jar files in its classpath.
-> When we reach that point, we should revisit the naming of it, and yes, maybe the simple "framework.jar" is a good option.
-> But again, for now, I want to make this change as transparent as possible to the rest of the world.
+The current structure is *not* the final design.
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index c2bdb6c..2f5f555 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -1157,22 +1157,14 @@
         private void removeAll(Predicate<JobStatus> predicate) {
             for (int jobSetIndex = mJobs.size() - 1; jobSetIndex >= 0; jobSetIndex--) {
                 final ArraySet<JobStatus> jobs = mJobs.valueAt(jobSetIndex);
-                for (int jobIndex = jobs.size() - 1; jobIndex >= 0; jobIndex--) {
-                    if (predicate.test(jobs.valueAt(jobIndex))) {
-                        jobs.removeAt(jobIndex);
-                    }
-                }
+                jobs.removeIf(predicate);
                 if (jobs.size() == 0) {
                     mJobs.removeAt(jobSetIndex);
                 }
             }
             for (int jobSetIndex = mJobsPerSourceUid.size() - 1; jobSetIndex >= 0; jobSetIndex--) {
                 final ArraySet<JobStatus> jobs = mJobsPerSourceUid.valueAt(jobSetIndex);
-                for (int jobIndex = jobs.size() - 1; jobIndex >= 0; jobIndex--) {
-                    if (predicate.test(jobs.valueAt(jobIndex))) {
-                        jobs.removeAt(jobIndex);
-                    }
-                }
+                jobs.removeIf(predicate);
                 if (jobs.size() == 0) {
                     mJobsPerSourceUid.removeAt(jobSetIndex);
                 }
diff --git a/apex/statsd/OWNERS b/apex/statsd/OWNERS
new file mode 100644
index 0000000..bed9600
--- /dev/null
+++ b/apex/statsd/OWNERS
@@ -0,0 +1,9 @@
+jeffreyhuang@google.com
+joeo@google.com
+jtnguyen@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
\ No newline at end of file
diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp
new file mode 100644
index 0000000..786e8b0
--- /dev/null
+++ b/apex/statsd/service/Android.bp
@@ -0,0 +1,16 @@
+// Statsd Service jar, which will eventually be put in the statsd mainline apex.
+// statsd-service needs to be added to PRODUCT_SYSTEM_SERVER_JARS.
+// This jar will contain StatsCompanionService
+java_library {
+    name: "statsd-service",
+    installable: true,
+
+    srcs: [
+        "java/**/*.java",
+    ],
+
+    libs: [
+        "framework",
+        "services.core",
+    ],
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
similarity index 97%
rename from services/core/java/com/android/server/stats/StatsCompanionService.java
rename to apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index 67830a9..1a10753 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -24,11 +24,10 @@
 import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
 
 import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
-import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs;
 import static com.android.server.stats.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
 import static com.android.server.stats.IonMemoryUtil.readSystemIonHeapSizeFromDebugfs;
+import static com.android.server.stats.ProcfsMemoryUtil.readCmdlineFromProcfs;
 import static com.android.server.stats.ProcfsMemoryUtil.readMemorySnapshotFromProcfs;
 
 import android.annotation.NonNull;
@@ -1193,48 +1192,13 @@
             e.writeLong(memoryStat.rssInBytes);
             e.writeLong(memoryStat.cacheInBytes);
             e.writeLong(memoryStat.swapInBytes);
-            e.writeLong(0);  // unused
-            e.writeLong(memoryStat.startTimeNanos);
-            e.writeInt(anonAndSwapInKilobytes(memoryStat));
+            e.writeLong(-1);  // unused
+            e.writeLong(-1);  // unused
+            e.writeInt(-1);  // unsed
             pulledData.add(e);
         }
     }
 
-    private void pullNativeProcessMemoryState(
-            int tagId, long elapsedNanos, long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
-        int[] pids = getPidsForCommands(MEMORY_INTERESTING_NATIVE_PROCESSES);
-        for (int pid : pids) {
-            String processName = readCmdlineFromProcfs(pid);
-            MemoryStat memoryStat = readMemoryStatFromProcfs(pid);
-            if (memoryStat == null) {
-                continue;
-            }
-            int uid = getUidForPid(pid);
-            // Sometimes we get here a process that is not included in the whitelist. It comes
-            // from forking the zygote for an app. We can ignore that sample because this process
-            // is collected by ProcessMemoryState.
-            if (isAppUid(uid)) {
-                continue;
-            }
-            StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
-            e.writeInt(uid);
-            e.writeString(processName);
-            e.writeLong(memoryStat.pgfault);
-            e.writeLong(memoryStat.pgmajfault);
-            e.writeLong(memoryStat.rssInBytes);
-            e.writeLong(0);  // unused
-            e.writeLong(memoryStat.startTimeNanos);
-            e.writeLong(memoryStat.swapInBytes);
-            e.writeInt(anonAndSwapInKilobytes(memoryStat));
-            pulledData.add(e);
-        }
-    }
-
-    private static int anonAndSwapInKilobytes(MemoryStat memoryStat) {
-        return (int) ((memoryStat.anonRssInBytes + memoryStat.swapInBytes) / 1024);
-    }
-
     private void pullProcessMemoryHighWaterMark(
             int tagId, long elapsedNanos, long wallClockNanos,
             List<StatsLogEventWrapper> pulledData) {
@@ -2115,9 +2079,6 @@
             HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                     TimeUnit.MILLISECONDS);
 
-            StatsLogEventWrapper e = new StatsLogEventWrapper(StatsLog.APP_OPS, elapsedNanos,
-                    wallClockNanos);
-
             for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
                 final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
                 final int uid = uidOps.getUid();
@@ -2125,6 +2086,9 @@
                     final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
                     for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
                         final AppOpsManager.HistoricalOp op  = packageOps.getOpAt(opIdx);
+                        StatsLogEventWrapper e = new StatsLogEventWrapper(StatsLog.APP_OPS,
+                                elapsedNanos, wallClockNanos);
+
                         e.writeInt(uid);
                         e.writeString(packageOps.getPackageName());
                         e.writeInt(op.getOpCode());
@@ -2405,10 +2369,6 @@
                 pullProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
-            case StatsLog.NATIVE_PROCESS_MEMORY_STATE: {
-                pullNativeProcessMemoryState(tagId, elapsedNanos, wallClockNanos, ret);
-                break;
-            }
             case StatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: {
                 pullProcessMemoryHighWaterMark(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
diff --git a/api/current.txt b/api/current.txt
index fc7685d..3ce043c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11395,7 +11395,7 @@
     method public abstract void onPackageRemoved(String, android.os.UserHandle);
     method public abstract void onPackagesAvailable(String[], android.os.UserHandle, boolean);
     method public void onPackagesSuspended(String[], android.os.UserHandle);
-    method public void onPackagesSuspended(String[], android.os.UserHandle, @Nullable android.os.Bundle);
+    method @Deprecated public void onPackagesSuspended(String[], android.os.UserHandle, @Nullable android.os.Bundle);
     method public abstract void onPackagesUnavailable(String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(String[], android.os.UserHandle);
     method public void onShortcutsChanged(@NonNull String, @NonNull java.util.List<android.content.pm.ShortcutInfo>, @NonNull android.os.UserHandle);
@@ -11908,6 +11908,7 @@
     field public static final int SIGNATURE_NO_MATCH = -3; // 0xfffffffd
     field public static final int SIGNATURE_SECOND_NOT_SIGNED = -2; // 0xfffffffe
     field public static final int SIGNATURE_UNKNOWN_PACKAGE = -4; // 0xfffffffc
+    field public static final int SYNCHRONOUS = 2; // 0x2
     field public static final int VERIFICATION_ALLOW = 1; // 0x1
     field public static final int VERIFICATION_REJECT = -1; // 0xffffffff
     field public static final int VERSION_CODE_HIGHEST = -1; // 0xffffffff
@@ -23133,10 +23134,10 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull String, long, float, @NonNull android.app.PendingIntent);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(long, float, @NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull String, @NonNull android.app.PendingIntent);
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestSingleUpdate(@NonNull android.location.Criteria, @NonNull android.app.PendingIntent);
     method public boolean sendExtraCommand(@NonNull String, @NonNull String, @Nullable android.os.Bundle);
     method public void setTestProviderEnabled(@NonNull String, boolean);
     method public void setTestProviderLocation(@NonNull String, @NonNull android.location.Location);
@@ -43171,6 +43172,7 @@
     field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
     field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
     field public static final int STATE_ACTIVE = 4; // 0x4
+    field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc
     field public static final int STATE_CONNECTING = 9; // 0x9
     field public static final int STATE_DIALING = 1; // 0x1
     field public static final int STATE_DISCONNECTED = 7; // 0x7
@@ -43180,6 +43182,7 @@
     field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
+    field public static final int STATE_SIMULATED_RINGING = 13; // 0xd
   }
 
   public abstract static class Call.Callback {
@@ -44291,6 +44294,7 @@
     field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
     field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
     field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
+    field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
     field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
@@ -53052,7 +53056,8 @@
     method @NonNull public android.view.autofill.AutofillId newAutofillId(@NonNull android.view.autofill.AutofillId, long);
     method @NonNull public final android.view.ViewStructure newViewStructure(@NonNull android.view.View);
     method @NonNull public final android.view.ViewStructure newVirtualViewStructure(@NonNull android.view.autofill.AutofillId, long);
-    method public final void notifySessionLifecycle(boolean);
+    method public final void notifySessionPaused();
+    method public final void notifySessionResumed();
     method public final void notifyViewAppeared(@NonNull android.view.ViewStructure);
     method public final void notifyViewDisappeared(@NonNull android.view.autofill.AutofillId);
     method public final void notifyViewTextChanged(@NonNull android.view.autofill.AutofillId, @Nullable CharSequence);
diff --git a/api/system-current.txt b/api/system-current.txt
index 279d2c8..a4e20cc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3431,9 +3431,9 @@
     method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public boolean isProviderPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
@@ -5901,7 +5901,8 @@
     field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
     field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
     field public static final String NAMESPACE_SCHEDULER = "scheduler";
-    field public static final String NAMESPACE_STORAGE = "storage";
+    field @Deprecated public static final String NAMESPACE_STORAGE = "storage";
+    field public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
     field public static final String NAMESPACE_SYSTEMUI = "systemui";
     field public static final String NAMESPACE_TELEPHONY = "telephony";
     field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
@@ -6966,6 +6967,8 @@
 
   public final class Call {
     method @Deprecated public void addListener(android.telecom.Call.Listener);
+    method public void enterBackgroundAudioProcessing();
+    method public void exitBackgroundAudioProcessing(boolean);
     method @Deprecated public void removeListener(android.telecom.Call.Listener);
     field @Deprecated public static final int STATE_PRE_DIAL_WAIT = 8; // 0x8
   }
@@ -6974,6 +6977,10 @@
     ctor @Deprecated public Call.Listener();
   }
 
+  public static class CallScreeningService.CallResponse.Builder {
+    method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean);
+  }
+
   public abstract class Conference extends android.telecom.Conferenceable {
     method @Deprecated public final android.telecom.AudioState getAudioState();
     method @Deprecated public final long getConnectTimeMillis();
@@ -7858,6 +7865,8 @@
     method public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
     method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onCallDisconnectCauseChanged(int, int);
     method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onImsCallDisconnectCauseChanged(@NonNull android.telephony.ims.ImsReasonInfo);
+    method public void onOutgoingEmergencyCall(@NonNull android.telephony.emergency.EmergencyNumber);
+    method public void onOutgoingEmergencySms(@NonNull android.telephony.emergency.EmergencyNumber);
     method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseCallStateChanged(@NonNull android.telephony.PreciseCallState);
     method @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public void onPreciseDataConnectionStateChanged(@NonNull android.telephony.PreciseDataConnectionState);
     method public void onRadioPowerStateChanged(int);
@@ -8236,7 +8245,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
     method public static long getMaxNumberVerificationTimeoutMillis();
-    method @NonNull public String getNetworkCountryIso(int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getNetworkCountryIso(int);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
     method public int getSimApplicationState();
@@ -8380,6 +8389,27 @@
 
 }
 
+package android.telephony.cdma {
+
+  public final class CdmaSmsCbProgramData implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getCategory();
+    method public int getOperation();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 4099; // 0x1003
+    field public static final int CATEGORY_CMAS_EXTREME_THREAT = 4097; // 0x1001
+    field public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE = 4351; // 0x10ff
+    field public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 4096; // 0x1000
+    field public static final int CATEGORY_CMAS_SEVERE_THREAT = 4098; // 0x1002
+    field public static final int CATEGORY_CMAS_TEST_MESSAGE = 4100; // 0x1004
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.cdma.CdmaSmsCbProgramData> CREATOR;
+    field public static final int OPERATION_ADD_CATEGORY = 1; // 0x1
+    field public static final int OPERATION_CLEAR_CATEGORIES = 2; // 0x2
+    field public static final int OPERATION_DELETE_CATEGORY = 0; // 0x0
+  }
+
+}
+
 package android.telephony.data {
 
   public final class DataCallResponse implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 75d80bd..a40cb92 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -786,7 +786,7 @@
 
   public final class AssetManager implements java.lang.AutoCloseable {
     method @NonNull public String[] getApkPaths();
-    method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOverlayableMap(String);
+    method @Nullable public String getOverlayablesToString(String);
   }
 
   public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable {
@@ -1093,9 +1093,9 @@
     method @NonNull public String[] getBackgroundThrottlingWhitelist();
     method @NonNull public String[] getIgnoreSettingsWhitelist();
     method @NonNull public java.util.List<android.location.LocationRequest> getTestProviderCurrentRequests(String);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
   }
 
@@ -2771,10 +2771,19 @@
 
 package android.telecom {
 
+  public final class Call {
+    method public void enterBackgroundAudioProcessing();
+    method public void exitBackgroundAudioProcessing(boolean);
+  }
+
   public final class CallAudioState implements android.os.Parcelable {
     ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>);
   }
 
+  public static class CallScreeningService.CallResponse.Builder {
+    method public android.telecom.CallScreeningService.CallResponse.Builder setShouldScreenCallFurther(boolean);
+  }
+
   public abstract class Conference extends android.telecom.Conferenceable {
     method public android.telecom.Connection getPrimaryConnection();
   }
@@ -2890,6 +2899,11 @@
     method public static void setMinMatchForTest(int);
   }
 
+  public class PhoneStateListener {
+    field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER = 268435456; // 0x10000000
+    field @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public static final int LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER = 536870912; // 0x20000000
+  }
+
   public class ServiceState implements android.os.Parcelable {
     method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
     method public void setCdmaSystemAndNetworkId(int, int);
@@ -2914,7 +2928,7 @@
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
-    method @NonNull public String getNetworkCountryIso(int);
+    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 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
@@ -2928,6 +2942,14 @@
 
 }
 
+package android.telephony.emergency {
+
+  public final class EmergencyNumber implements java.lang.Comparable<android.telephony.emergency.EmergencyNumber> android.os.Parcelable {
+    field public static final int EMERGENCY_NUMBER_SOURCE_TEST = 32; // 0x20
+  }
+
+}
+
 package android.telephony.mbms {
 
   public static class DownloadRequest.Builder {
@@ -3350,6 +3372,7 @@
   public class WindowlessViewRoot {
     ctor public WindowlessViewRoot(android.content.Context, android.view.Display, android.view.SurfaceControl);
     method public void addView(android.view.View, android.view.WindowManager.LayoutParams);
+    method public void relayout(android.view.WindowManager.LayoutParams);
   }
 
 }
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index bb8d927..f482191 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -50,7 +50,7 @@
   std::string overlay_apk_path;
   std::string idmap_path;
   std::vector<std::string> policies;
-  bool ignore_overlayable;
+  bool ignore_overlayable = false;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 create")
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 8716bf3..47f442a 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -39,7 +39,7 @@
 Result<Unit> Dump(const std::vector<std::string>& args) {
   SYSTRACE << "Dump " << args;
   std::string idmap_path;
-  bool verbose;
+  bool verbose = false;
 
   const CommandLineOptions opts =
       CommandLineOptions("idmap2 dump")
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 053b7bc..d0530f2 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -178,6 +178,17 @@
       continue;
     }
 
+    // Note that conditional property enablement/exclusion only applies if
+    // the attribute is present. In its absence, all overlays are presumed enabled.
+    if (!overlay_info->requiredSystemPropertyName.empty()
+        && !overlay_info->requiredSystemPropertyValue.empty()) {
+      // if property set & equal to value, then include overlay - otherwise skip
+      if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "")
+          != overlay_info->requiredSystemPropertyValue) {
+        continue;
+      }
+    }
+
     std::vector<std::string> fulfilled_policies;
     if (!override_policies.empty()) {
       fulfilled_policies = override_policies;
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 8797a78..9a0c2ab 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -30,6 +30,8 @@
 struct OverlayManifestInfo {
   std::string target_package;  // NOLINT(misc-non-private-member-variables-in-classes)
   std::string target_name;     // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string requiredSystemPropertyName;  // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string requiredSystemPropertyValue;  // NOLINT(misc-non-private-member-variables-in-classes)
   bool is_static;              // NOLINT(misc-non-private-member-variables-in-classes)
   int priority = -1;           // NOLINT(misc-non-private-member-variables-in-classes)
 };
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 71ba3f0..dce83e3 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -103,6 +103,16 @@
     info.priority = std::stoi(iter->second);
   }
 
+  iter = tag->find("requiredSystemPropertyName");
+  if (iter != tag->end()) {
+    info.requiredSystemPropertyName = iter->second;
+  }
+
+  iter = tag->find("requiredSystemPropertyValue");
+  if (iter != tag->end()) {
+    info.requiredSystemPropertyValue = iter->second;
+  }
+
   return info;
 }
 
diff --git a/cmds/idmap2/libidmap2/ZipFile.cpp b/cmds/idmap2/libidmap2/ZipFile.cpp
index 4f5e3a4..1e1a218 100644
--- a/cmds/idmap2/libidmap2/ZipFile.cpp
+++ b/cmds/idmap2/libidmap2/ZipFile.cpp
@@ -34,6 +34,7 @@
   ::ZipArchiveHandle handle;
   int32_t status = ::OpenArchive(path.c_str(), &handle);
   if (status != 0) {
+    ::CloseArchive(handle);
     return nullptr;
   }
   return std::unique_ptr<ZipFile>(new ZipFile(handle));
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index 41d3c69..a372abd 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -27,10 +27,11 @@
     local red="\e[31m"
     local green="\e[32m"
     local reset="\e[0m"
+    local output
 
     _log "${green}[ RUN      ]${reset} ${label}"
-    local output="$(eval "$cmd")"
-    if [[ -z "${output}" ]]; then
+    output="$(eval "$cmd" 2>&1)"
+    if [[ $? -eq 0 ]]; then
         _log "${green}[       OK ]${reset} ${label}"
         return 0
     else
diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh
new file mode 100755
index 0000000..b4ebab0
--- /dev/null
+++ b/cmds/idmap2/valgrind.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# 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.
+#
+
+function _log()
+{
+    echo -e "$*" >&2
+}
+
+function _eval()
+{
+    local label="$1"
+    local cmd="$2"
+    local red="\e[31m"
+    local green="\e[32m"
+    local reset="\e[0m"
+    local output
+
+    _log "${green}[ RUN      ]${reset} ${label}"
+    output="$(eval "$cmd" 2>&1)"
+    if [[ $? -eq 0 ]]; then
+        _log "${green}[       OK ]${reset} ${label}"
+        return 0
+    else
+        echo "${output}"
+        _log "${red}[  FAILED  ]${reset} ${label}"
+        errors=$((errors + 1))
+        return 1
+    fi
+}
+
+errors=0
+script="$(readlink -f "$BASH_SOURCE")"
+prefix="$(dirname "$script")"
+target_path="${prefix}/tests/data/target/target.apk"
+overlay_path="${prefix}/tests/data/overlay/overlay.apk"
+idmap_path="/tmp/a.idmap"
+valgrind="valgrind --error-exitcode=1 -q --track-origins=yes --leak-check=full"
+
+_eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path"
+_eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path"
+_eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1"
+_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public"
+_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path"
+_eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests"
+exit $errors
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index c79b0ca..cb27325 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -138,6 +138,7 @@
         "libprotoutil",
         "libservices",
         "libstatslog",
+        "libstatssocket",
         "libsysutils",
         "libtimestats_proto",
         "libutils",
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b71a86b..6249de3 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -378,7 +378,6 @@
         PowerProfile power_profile = 10033;
         ProcStatsPkgProc proc_stats_pkg_proc = 10034;
         ProcessCpuTime process_cpu_time = 10035;
-        NativeProcessMemoryState native_process_memory_state = 10036;
         CpuTimePerThreadFreq cpu_time_per_thread_freq = 10037;
         OnDevicePowerMeasurement on_device_power_measurement = 10038;
         DeviceCalculatedPowerUse device_calculated_power_use = 10039;
@@ -412,6 +411,8 @@
     // DO NOT USE field numbers above 100,000 in AOSP.
     // Field numbers 100,000 - 199,999 are reserved for non-AOSP (e.g. OEMs) to use.
     // Field numbers 200,000 and above are reserved for future use; do not use them at all.
+
+    reserved 10036;
 }
 
 /**
@@ -4019,8 +4020,8 @@
     optional int64 page_major_fault = 5;
 
     // RSS
-    // Value is read from /proc/PID/status. Or from memory.stat, field
-    // total_rss if per-app memory cgroups are enabled.
+    // Value is read from memory.stat, field total_rss if per-app memory
+    // cgroups are enabled. Otherwise, value from /proc/pid/stat.
     optional int64 rss_in_bytes = 6;
 
     // CACHE
@@ -4030,56 +4031,17 @@
 
     // SWAP
     // Value is read from memory.stat, field total_swap if per-app memory
-    // cgroups are enabled. Otherwise, VmSwap from /proc/PID/status.
+    // cgroups are enabled. Otherwise, 0.
     optional int64 swap_in_bytes = 8;
 
-    // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
+    // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always -1.
     optional int64 rss_high_watermark_in_bytes = 9 [deprecated = true];
 
-    // Elapsed real time when the process started.
-    // Value is read from /proc/PID/stat, field 22. 0 if read from per-app memory cgroups.
-    optional int64 start_time_nanos = 10;
+    // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+    optional int64 start_time_nanos = 10 [deprecated = true];
 
-    // Anonymous page size plus swap size. Values are read from /proc/PID/status.
-    optional int32 anon_rss_and_swap_in_kilobytes = 11;
-}
-
-/*
- * Logs the memory stats for a native process (from procfs).
- *
- * Pulled from StatsCompanionService for selected native processes.
- */
-message NativeProcessMemoryState {
-    // The uid if available. -1 means not available.
-    optional int32 uid = 1 [(is_uid) = true];
-
-    // The process name.
-    // Value read from /proc/PID/cmdline.
-    optional string process_name = 2;
-
-    // # of page-faults
-    optional int64 page_fault = 3;
-
-    // # of major page-faults
-    optional int64 page_major_fault = 4;
-
-    // RSS
-    // Value read from /proc/PID/status.
-    optional int64 rss_in_bytes = 5;
-
-    // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0.
-    optional int64 rss_high_watermark_in_bytes = 6 [deprecated = true];
-
-    // Elapsed real time when the process started.
-    // Value is read from /proc/PID/stat, field 22.
-    optional int64 start_time_nanos = 7;
-
-    // SWAP
-    // Value read from /proc/PID/status, field VmSwap.
-    optional int64 swap_in_bytes = 8;
-
-    // Anonymous page size plus swap size. Values are read from /proc/PID/status.
-    optional int32 anon_rss_and_swap_in_kilobytes = 9;
+    // Deprecated: use ProcessMemorySnapshot atom instead. Always -1.
+    optional int32 anon_rss_and_swap_in_kilobytes = 11 [deprecated = true];
 }
 
 /*
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index bbdb540..d38b87f 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -92,9 +92,15 @@
                 android::util::GPU_STATS_APP_INFO, getWallClockNs(), getElapsedRealtimeNs());
         if (!event->write(info.appPackageName)) return false;
         if (!event->write((int64_t)info.driverVersionCode)) return false;
-        if (!event->write(int64VectorToProtoByteString(info.glDriverLoadingTime))) return false;
-        if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
-        if (!event->write(int64VectorToProtoByteString(info.angleDriverLoadingTime))) return false;
+        if (!event->writeBytes(int64VectorToProtoByteString(info.glDriverLoadingTime)))  {
+            return false;
+        }
+        if (!event->writeBytes(int64VectorToProtoByteString(info.vkDriverLoadingTime))) {
+            return false;
+        }
+        if (!event->writeBytes(int64VectorToProtoByteString(info.angleDriverLoadingTime))) {
+            return false;
+        }
         if (!event->write(info.cpuVulkanInUse)) return false;
         if (!event->write(info.falsePrerotation)) return false;
         event->init();
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 7a183a3..43e33f5 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -145,16 +145,11 @@
          {.puller = new ResourceHealthManagerPuller(android::util::BATTERY_CYCLE_COUNT)}},
         // process_memory_state
         {android::util::PROCESS_MEMORY_STATE,
-         {.additiveFields = {4, 5, 6, 7, 8, 9},
+         {.additiveFields = {4, 5, 6, 7, 8},
           .puller = new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
-        // native_process_memory_state
-        {android::util::NATIVE_PROCESS_MEMORY_STATE,
-         {.additiveFields = {3, 4, 5, 6, 8},
-          .puller = new StatsCompanionServicePuller(android::util::NATIVE_PROCESS_MEMORY_STATE)}},
         // process_memory_high_water_mark
         {android::util::PROCESS_MEMORY_HIGH_WATER_MARK,
-         {.additiveFields = {3},
-          .puller =
+         {.puller =
                   new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_HIGH_WATER_MARK)}},
         // process_memory_snapshot
         {android::util::PROCESS_MEMORY_SNAPSHOT,
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 0ade5311..fd19c9d 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -332,6 +332,13 @@
     return false;
 }
 
+bool LogEvent::writeBytes(const string& value) {
+    if (mContext) {
+        return android_log_write_char_array(mContext, value.c_str(), value.length()) >= 0;
+    }
+    return false;
+}
+
 bool LogEvent::writeKeyValuePairs(int32_t uid,
                                   const std::map<int32_t, int32_t>& int_map,
                                   const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 531ce29..f1f45a2 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -21,9 +21,9 @@
 #include <android/frameworks/stats/1.0/types.h>
 #include <android/os/StatsLogEventWrapper.h>
 #include <android/util/ProtoOutputStream.h>
-#include <log/log_event_list.h>
 #include <log/log_read.h>
 #include <private/android_logger.h>
+#include <stats_event_list.h>
 #include <utils/Errors.h>
 
 #include <string>
@@ -157,6 +157,7 @@
     bool write(float value);
     bool write(const std::vector<AttributionNodeInternal>& nodes);
     bool write(const AttributionNodeInternal& node);
+    bool writeBytes(const std::string& value);
     bool writeKeyValuePairs(int32_t uid,
                             const std::map<int32_t, int32_t>& int_map,
                             const std::map<int32_t, int64_t>& long_map,
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 504ee22..0743480 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -582,7 +582,7 @@
     event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
     event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
     event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
-    event1.write(extension_str);
+    event1.writeBytes(extension_str);
     event1.init();
 
     ProtoOutputStream proto;
@@ -621,7 +621,7 @@
     event1.write((int32_t)stats::launcher::LauncherAction::LONGPRESS);
     event1.write((int32_t)stats::launcher::LauncherState::OVERVIEW);
     event1.write((int64_t)stats::launcher::LauncherState::ALLAPPS);
-    event1.write(extension_str);
+    event1.writeBytes(extension_str);
     event1.init();
 
     ProtoOutputStream proto;
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index e0f7d86..c9f069d 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -65,11 +65,21 @@
     private static final String COMMAND_UNREGISTER_PHONE_ACCOUNT = "unregister-phone-account";
     private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
     private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
+    /**
+     * Change the system dialer package name if a package name was specified,
+     * Example: adb shell telecom set-system-dialer <PACKAGE>
+     *
+     * Restore it to the default if if argument is "default" or no argument is passed.
+     * Example: adb shell telecom set-system-dialer default
+     */
+    private static final String COMMAND_SET_SYSTEM_DIALER = "set-system-dialer";
     private static final String COMMAND_GET_SYSTEM_DIALER = "get-system-dialer";
     private static final String COMMAND_WAIT_ON_HANDLERS = "wait-on-handlers";
     private static final String COMMAND_SET_SIM_COUNT = "set-sim-count";
     private static final String COMMAND_GET_SIM_CONFIG = "get-sim-config";
     private static final String COMMAND_GET_MAX_PHONES = "get-max-phones";
+    private static final String COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER =
+            "set-test-emergency-phone-account-package-filter";
 
     private ComponentName mComponent;
     private String mAccountId;
@@ -83,7 +93,10 @@
                 + "usage: telecom set-phone-account-enabled <COMPONENT> <ID> <USER_SN>\n"
                 + "usage: telecom set-phone-account-disabled <COMPONENT> <ID> <USER_SN>\n"
                 + "usage: telecom register-phone-account <COMPONENT> <ID> <USER_SN> <LABEL>\n"
-                + "usage: telecom set-user-selected-outgoing-phone-account <COMPONENT> <ID> "
+                + "usage: telecom register-sim-phone-account [-e] <COMPONENT> <ID> <USER_SN>"
+                        + " <LABEL>: registers a PhoneAccount with CAPABILITY_SIM_SUBSCRIPTION"
+                        + " and optionally CAPABILITY_PLACE_EMERGENCY_CALLS if \"-e\" is provided\n"
+                + "usage: telecom set-user-selected-outgoing-phone-account [-e] <COMPONENT> <ID> "
                 + "<USER_SN>\n"
                 + "usage: telecom set-test-call-redirection-app <PACKAGE>\n"
                 + "usage: telecom set-test-call-screening-app <PACKAGE>\n"
@@ -100,6 +113,7 @@
                 + "usage: telecom set-sim-count <COUNT>\n"
                 + "usage: telecom get-sim-config\n"
                 + "usage: telecom get-max-phones\n"
+                + "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
                 + "\n"
                 + "telecom set-phone-account-enabled: Enables the given phone account, if it has"
                         + " already been registered with Telecom.\n"
@@ -113,6 +127,8 @@
                 + "telecom get-default-dialer: Displays the current default dialer.\n"
                 + "\n"
                 + "telecom get-system-dialer: Displays the current system dialer.\n"
+                + "telecom set-system-dialer: Set the override system dialer to the given"
+                        + " component. To remove the override, send \"default\"\n"
                 + "\n"
                 + "telecom wait-on-handlers: Wait until all handlers finish their work.\n"
                 + "\n"
@@ -123,6 +139,10 @@
                         + " or \"\" for single SIM\n"
                 + "\n"
                 + "telecom get-max-phones: Get the max supported phones from the modem.\n"
+                + "telecom set-test-emergency-phone-account-package-filter <PACKAGE>: sets a"
+                        + " package name that will be used for test emergency calls. To clear,"
+                        + " send an empty package name. Real emergency calls will still be placed"
+                        + " over Telephony.\n"
         );
     }
 
@@ -193,6 +213,9 @@
             case COMMAND_GET_DEFAULT_DIALER:
                 runGetDefaultDialer();
                 break;
+            case COMMAND_SET_SYSTEM_DIALER:
+                runSetSystemDialer();
+                break;
             case COMMAND_GET_SYSTEM_DIALER:
                 runGetSystemDialer();
                 break;
@@ -208,6 +231,9 @@
             case COMMAND_GET_MAX_PHONES:
                 runGetMaxPhones();
                 break;
+            case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER:
+                runSetEmergencyPhoneAccountPackageFilter();
+                break;
             default:
                 Log.w(this, "onRun: unknown command: %s", command);
                 throw new IllegalArgumentException ("unknown command '" + command + "'");
@@ -234,19 +260,31 @@
     }
 
     private void runRegisterSimPhoneAccount() throws RemoteException {
+        boolean isEmergencyAccount = false;
+        String opt;
+        while ((opt = nextOption()) != null) {
+            switch (opt) {
+                case "-e": {
+                    isEmergencyAccount = true;
+                    break;
+                }
+            }
+        }
         final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
         final String label = nextArgRequired();
         final String address = nextArgRequired();
+        int capabilities = PhoneAccount.CAPABILITY_CALL_PROVIDER
+                | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION
+                | (isEmergencyAccount ? PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS : 0);
         PhoneAccount account = PhoneAccount.builder(
             handle, label)
-            .setAddress(Uri.parse(address))
-            .setSubscriptionAddress(Uri.parse(address))
-            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
-                    PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
-            .setShortDescription(label)
-            .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
-            .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
-            .build();
+                .setAddress(Uri.parse(address))
+                .setSubscriptionAddress(Uri.parse(address))
+                .setCapabilities(capabilities)
+                .setShortDescription(label)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+                .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+                .build();
         mTelecomService.registerPhoneAccount(account);
         System.out.println("Success - " + handle + " registered.");
     }
@@ -297,6 +335,14 @@
         System.out.println("Success - " + packageName + " set as override default dialer.");
     }
 
+    private void runSetSystemDialer() throws RemoteException {
+        final String flatComponentName = nextArg();
+        final ComponentName componentName = (flatComponentName.equals("default")
+                ? null : parseComponentName(flatComponentName));
+        mTelecomService.setSystemDialer(componentName);
+        System.out.println("Success - " + componentName + " set as override system dialer.");
+    }
+
     private void runGetDefaultDialer() throws RemoteException {
         System.out.println(mTelecomService.getDefaultDialerPackage());
     }
@@ -338,6 +384,18 @@
         }
     }
 
+    private void runSetEmergencyPhoneAccountPackageFilter() throws RemoteException {
+        String packageName = mArgs.getNextArg();
+        if (TextUtils.isEmpty(packageName)) {
+            mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(null);
+            System.out.println("Success - filter cleared");
+        } else {
+            mTelecomService.setTestEmergencyPhoneAccountPackageNameFilter(packageName);
+            System.out.println("Success = filter set to " + packageName);
+        }
+
+    }
+
     private PhoneAccountHandle getPhoneAccountHandleFromArgs() throws RemoteException {
         if (TextUtils.isEmpty(mArgs.peekNextArg())) {
             return null;
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index e1cf7c1..3cb2273 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1182,284 +1182,4 @@
 Lcom/android/server/ResettableTimeout$T;-><init>(Lcom/android/server/ResettableTimeout;)V
 Lcom/google/android/gles_jni/EGLImpl;-><init>()V
 Lcom/google/android/gles_jni/GLImpl;-><init>()V
-Lcom/google/android/mms/ContentType;->getAudioTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getImageTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->getVideoTypes()Ljava/util/ArrayList;
-Lcom/google/android/mms/ContentType;->isAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isDrmType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedAudioType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedImageType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isSupportedVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isTextType(Ljava/lang/String;)Z
-Lcom/google/android/mms/ContentType;->isVideoType(Ljava/lang/String;)Z
-Lcom/google/android/mms/InvalidHeaderValueException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>()V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/String;Ljava/lang/Throwable;)V
-Lcom/google/android/mms/MmsException;-><init>(Ljava/lang/Throwable;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(I[B)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/AcknowledgeInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/Base64;->decodeBase64([B)[B
-Lcom/google/android/mms/pdu/CharacterSets;->getMibEnumValue(Ljava/lang/String;)I
-Lcom/google/android/mms/pdu/CharacterSets;->getMimeName(I)Ljava/lang/String;
-Lcom/google/android/mms/pdu/DeliveryInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/DeliveryInd;->getDate()J
-Lcom/google/android/mms/pdu/DeliveryInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/DeliveryInd;->getStatus()I
-Lcom/google/android/mms/pdu/DeliveryInd;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(I[B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/EncodedStringValue;-><init>([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->appendTextString([B)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->concat([Lcom/google/android/mms/pdu/EncodedStringValue;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->copy(Lcom/google/android/mms/pdu/EncodedStringValue;)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->encodeStrings([Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->extract(Ljava/lang/String;)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getCharacterSet()I
-Lcom/google/android/mms/pdu/EncodedStringValue;->getString()Ljava/lang/String;
-Lcom/google/android/mms/pdu/EncodedStringValue;->getTextString()[B
-Lcom/google/android/mms/pdu/EncodedStringValue;->setCharacterSet(I)V
-Lcom/google/android/mms/pdu/EncodedStringValue;->setTextString([B)V
-Lcom/google/android/mms/pdu/GenericPdu;-><init>()V
-Lcom/google/android/mms/pdu/GenericPdu;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/GenericPdu;->getMessageType()I
-Lcom/google/android/mms/pdu/GenericPdu;->getPduHeaders()Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->mPduHeaders:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/GenericPdu;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/GenericPdu;->setMessageType(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>()V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->addTo(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getBody()Lcom/google/android/mms/pdu/PduBody;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getDate()J
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getPriority()I
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->getTo()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setBody(Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setDate(J)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setPriority(I)V
-Lcom/google/android/mms/pdu/MultimediaMessagePdu;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>()V
-Lcom/google/android/mms/pdu/NotificationInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotificationInd;->getContentClass()I
-Lcom/google/android/mms/pdu/NotificationInd;->getContentLocation()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/NotificationInd;->getExpiry()J
-Lcom/google/android/mms/pdu/NotificationInd;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageClass()[B
-Lcom/google/android/mms/pdu/NotificationInd;->getMessageSize()J
-Lcom/google/android/mms/pdu/NotificationInd;->getSubject()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/NotificationInd;->getTransactionId()[B
-Lcom/google/android/mms/pdu/NotificationInd;->setContentClass(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/NotificationInd;->setExpiry(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/NotificationInd;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/NotificationInd;->setSubject(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/NotificationInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(I[BI)V
-Lcom/google/android/mms/pdu/NotifyRespInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setReportAllowed(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setStatus(I)V
-Lcom/google/android/mms/pdu/NotifyRespInd;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/PduBody;-><init>()V
-Lcom/google/android/mms/pdu/PduBody;->addPart(ILcom/google/android/mms/pdu/PduPart;)V
-Lcom/google/android/mms/pdu/PduBody;->addPart(Lcom/google/android/mms/pdu/PduPart;)Z
-Lcom/google/android/mms/pdu/PduBody;->getPart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentId(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByContentLocation(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByFileName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartByName(Ljava/lang/String;)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduBody;->getPartIndex(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduBody;->getPartsNum()I
-Lcom/google/android/mms/pdu/PduBody;->removePart(I)Lcom/google/android/mms/pdu/PduPart;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->copy()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->mark()Lcom/google/android/mms/pdu/PduComposer$PositionMarker;
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->newbuf()V
-Lcom/google/android/mms/pdu/PduComposer$BufferStack;->pop()V
-Lcom/google/android/mms/pdu/PduComposer$PositionMarker;->getLength()I
-Lcom/google/android/mms/pdu/PduComposer;-><init>(Landroid/content/Context;Lcom/google/android/mms/pdu/GenericPdu;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendEncodedString(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendHeader(I)I
-Lcom/google/android/mms/pdu/PduComposer;->appendLongInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendOctet(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendQuotedString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendShortInteger(I)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduComposer;->appendTextString([B)V
-Lcom/google/android/mms/pdu/PduComposer;->appendUintvarInteger(J)V
-Lcom/google/android/mms/pdu/PduComposer;->appendValueLength(J)V
-Lcom/google/android/mms/pdu/PduComposer;->arraycopy([BII)V
-Lcom/google/android/mms/pdu/PduComposer;->make()[B
-Lcom/google/android/mms/pdu/PduComposer;->mContentTypeMap:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduComposer;->mMessage:Ljava/io/ByteArrayOutputStream;
-Lcom/google/android/mms/pdu/PduComposer;->mPdu:Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduComposer;->mPduHeader:Lcom/google/android/mms/pdu/PduHeaders;
-Lcom/google/android/mms/pdu/PduComposer;->mPosition:I
-Lcom/google/android/mms/pdu/PduComposer;->mResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduComposer;->mStack:Lcom/google/android/mms/pdu/PduComposer$BufferStack;
-Lcom/google/android/mms/pdu/PduContentTypes;->contentTypes:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduHeaders;-><init>()V
-Lcom/google/android/mms/pdu/PduHeaders;->appendEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValue(I)Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getEncodedStringValues(I)[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/PduHeaders;->getLongInteger(I)J
-Lcom/google/android/mms/pdu/PduHeaders;->getOctet(I)I
-Lcom/google/android/mms/pdu/PduHeaders;->getTextString(I)[B
-Lcom/google/android/mms/pdu/PduHeaders;->setEncodedStringValue(Lcom/google/android/mms/pdu/EncodedStringValue;I)V
-Lcom/google/android/mms/pdu/PduHeaders;->setLongInteger(JI)V
-Lcom/google/android/mms/pdu/PduHeaders;->setOctet(II)V
-Lcom/google/android/mms/pdu/PduParser;-><init>([BZ)V
-Lcom/google/android/mms/pdu/PduParser;->checkPartPosition(Lcom/google/android/mms/pdu/PduPart;)I
-Lcom/google/android/mms/pdu/PduParser;->log(Ljava/lang/String;)V
-Lcom/google/android/mms/pdu/PduParser;->parse()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduParser;->parseContentType(Ljava/io/ByteArrayInputStream;Ljava/util/HashMap;)[B
-Lcom/google/android/mms/pdu/PduParser;->parsePartHeaders(Ljava/io/ByteArrayInputStream;Lcom/google/android/mms/pdu/PduPart;I)Z
-Lcom/google/android/mms/pdu/PduParser;->parseShortInteger(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseUnsignedInt(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseValueLength(Ljava/io/ByteArrayInputStream;)I
-Lcom/google/android/mms/pdu/PduParser;->parseWapString(Ljava/io/ByteArrayInputStream;I)[B
-Lcom/google/android/mms/pdu/PduPart;-><init>()V
-Lcom/google/android/mms/pdu/PduPart;->generateLocation()Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPart;->getCharset()I
-Lcom/google/android/mms/pdu/PduPart;->getContentDisposition()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentId()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentLocation()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentTransferEncoding()[B
-Lcom/google/android/mms/pdu/PduPart;->getContentType()[B
-Lcom/google/android/mms/pdu/PduPart;->getData()[B
-Lcom/google/android/mms/pdu/PduPart;->getDataLength()I
-Lcom/google/android/mms/pdu/PduPart;->getDataUri()Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPart;->getFilename()[B
-Lcom/google/android/mms/pdu/PduPart;->getName()[B
-Lcom/google/android/mms/pdu/PduPart;->setCharset(I)V
-Lcom/google/android/mms/pdu/PduPart;->setContentDisposition([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentId([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentLocation([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentTransferEncoding([B)V
-Lcom/google/android/mms/pdu/PduPart;->setContentType([B)V
-Lcom/google/android/mms/pdu/PduPart;->setData([B)V
-Lcom/google/android/mms/pdu/PduPart;->setDataUri(Landroid/net/Uri;)V
-Lcom/google/android/mms/pdu/PduPart;->setFilename([B)V
-Lcom/google/android/mms/pdu/PduPart;->setName([B)V
-Lcom/google/android/mms/pdu/PduPersister;->ADDRESS_FIELDS:[I
-Lcom/google/android/mms/pdu/PduPersister;->CHARSET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->ENCODED_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->getByteArrayFromPartColumn(Landroid/database/Cursor;I)[B
-Lcom/google/android/mms/pdu/PduPersister;->getBytes(Ljava/lang/String;)[B
-Lcom/google/android/mms/pdu/PduPersister;->getIntegerFromPartColumn(Landroid/database/Cursor;I)Ljava/lang/Integer;
-Lcom/google/android/mms/pdu/PduPersister;->getPartContentType(Lcom/google/android/mms/pdu/PduPart;)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->getPduPersister(Landroid/content/Context;)Lcom/google/android/mms/pdu/PduPersister;
-Lcom/google/android/mms/pdu/PduPersister;->getPendingMessages(J)Landroid/database/Cursor;
-Lcom/google/android/mms/pdu/PduPersister;->load(Landroid/net/Uri;)Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/pdu/PduPersister;->loadRecipients(ILjava/util/HashSet;Ljava/util/HashMap;Z)V
-Lcom/google/android/mms/pdu/PduPersister;->LONG_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->mContentResolver:Landroid/content/ContentResolver;
-Lcom/google/android/mms/pdu/PduPersister;->mContext:Landroid/content/Context;
-Lcom/google/android/mms/pdu/PduPersister;->MESSAGE_BOX_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->move(Landroid/net/Uri;Landroid/net/Uri;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->mTelephonyManager:Landroid/telephony/TelephonyManager;
-Lcom/google/android/mms/pdu/PduPersister;->OCTET_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->PART_PROJECTION:[Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->PDU_CACHE_INSTANCE:Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/pdu/PduPersister;->persist(Lcom/google/android/mms/pdu/GenericPdu;Landroid/net/Uri;ZZLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->persistAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->persistPart(Lcom/google/android/mms/pdu/PduPart;JLjava/util/HashMap;)Landroid/net/Uri;
-Lcom/google/android/mms/pdu/PduPersister;->TEXT_STRING_COLUMN_NAME_MAP:Ljava/util/HashMap;
-Lcom/google/android/mms/pdu/PduPersister;->toIsoString([B)Ljava/lang/String;
-Lcom/google/android/mms/pdu/PduPersister;->updateAddress(JI[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateHeaders(Landroid/net/Uri;Lcom/google/android/mms/pdu/SendReq;)V
-Lcom/google/android/mms/pdu/PduPersister;->updateParts(Landroid/net/Uri;Lcom/google/android/mms/pdu/PduBody;Ljava/util/HashMap;)V
-Lcom/google/android/mms/pdu/QuotedPrintable;->decodeQuotedPrintable([B)[B
-Lcom/google/android/mms/pdu/ReadOrigInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadOrigInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadOrigInd;->getReadStatus()I
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/EncodedStringValue;[BII[Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/ReadRecInd;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/ReadRecInd;->getMessageId()[B
-Lcom/google/android/mms/pdu/ReadRecInd;->setDate(J)V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>()V
-Lcom/google/android/mms/pdu/RetrieveConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getContentType()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getFrom()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageClass()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->getReadReport()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveStatus()I
-Lcom/google/android/mms/pdu/RetrieveConf;->getRetrieveText()Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/RetrieveConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/RetrieveConf;->setContentType([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setFrom(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setMessageId([B)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setReadReport(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveStatus(I)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setRetrieveText(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/RetrieveConf;->setTransactionId([B)V
-Lcom/google/android/mms/pdu/SendConf;-><init>()V
-Lcom/google/android/mms/pdu/SendConf;-><init>(Lcom/google/android/mms/pdu/PduHeaders;)V
-Lcom/google/android/mms/pdu/SendConf;->getMessageId()[B
-Lcom/google/android/mms/pdu/SendConf;->getResponseStatus()I
-Lcom/google/android/mms/pdu/SendConf;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;-><init>()V
-Lcom/google/android/mms/pdu/SendReq;-><init>(Lcom/google/android/mms/pdu/PduHeaders;Lcom/google/android/mms/pdu/PduBody;)V
-Lcom/google/android/mms/pdu/SendReq;->addBcc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->addCc(Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->getBcc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getCc()[Lcom/google/android/mms/pdu/EncodedStringValue;
-Lcom/google/android/mms/pdu/SendReq;->getContentType()[B
-Lcom/google/android/mms/pdu/SendReq;->getDeliveryReport()I
-Lcom/google/android/mms/pdu/SendReq;->getExpiry()J
-Lcom/google/android/mms/pdu/SendReq;->getMessageClass()[B
-Lcom/google/android/mms/pdu/SendReq;->getMessageSize()J
-Lcom/google/android/mms/pdu/SendReq;->getReadReport()I
-Lcom/google/android/mms/pdu/SendReq;->getTransactionId()[B
-Lcom/google/android/mms/pdu/SendReq;->setBcc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setCc([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setContentType([B)V
-Lcom/google/android/mms/pdu/SendReq;->setDeliveryReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setExpiry(J)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageClass([B)V
-Lcom/google/android/mms/pdu/SendReq;->setMessageSize(J)V
-Lcom/google/android/mms/pdu/SendReq;->setReadReport(I)V
-Lcom/google/android/mms/pdu/SendReq;->setTo([Lcom/google/android/mms/pdu/EncodedStringValue;)V
-Lcom/google/android/mms/pdu/SendReq;->setTransactionId([B)V
-Lcom/google/android/mms/util/AbstractCache;-><init>()V
-Lcom/google/android/mms/util/AbstractCache;->get(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/AbstractCache;->purgeAll()V
-Lcom/google/android/mms/util/AbstractCache;->put(Ljava/lang/Object;Ljava/lang/Object;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->isDrmConvertNeeded(Ljava/lang/String;)Z
-Lcom/google/android/mms/util/DownloadDrmHelper;->modifyDrmFwLockFileExtension(Ljava/lang/String;)Ljava/lang/String;
-Lcom/google/android/mms/util/DrmConvertSession;->close(Ljava/lang/String;)I
-Lcom/google/android/mms/util/DrmConvertSession;->convert([BI)[B
-Lcom/google/android/mms/util/DrmConvertSession;->open(Landroid/content/Context;Ljava/lang/String;)Lcom/google/android/mms/util/DrmConvertSession;
-Lcom/google/android/mms/util/PduCache;-><init>()V
-Lcom/google/android/mms/util/PduCache;->getInstance()Lcom/google/android/mms/util/PduCache;
-Lcom/google/android/mms/util/PduCache;->isUpdating(Landroid/net/Uri;)Z
-Lcom/google/android/mms/util/PduCache;->purge(Landroid/net/Uri;)Lcom/google/android/mms/util/PduCacheEntry;
-Lcom/google/android/mms/util/PduCache;->purge(Ljava/lang/Object;)Ljava/lang/Object;
-Lcom/google/android/mms/util/PduCache;->purgeAll()V
-Lcom/google/android/mms/util/PduCacheEntry;-><init>(Lcom/google/android/mms/pdu/GenericPdu;IJ)V
-Lcom/google/android/mms/util/PduCacheEntry;->getMessageBox()I
-Lcom/google/android/mms/util/PduCacheEntry;->getPdu()Lcom/google/android/mms/pdu/GenericPdu;
-Lcom/google/android/mms/util/PduCacheEntry;->getThreadId()J
-Lcom/google/android/mms/util/SqliteWrapper;->checkSQLiteException(Landroid/content/Context;Landroid/database/sqlite/SQLiteException;)V
-Lcom/google/android/mms/util/SqliteWrapper;->delete(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
-Lcom/google/android/mms/util/SqliteWrapper;->insert(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
-Lcom/google/android/mms/util/SqliteWrapper;->query(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
-Lcom/google/android/mms/util/SqliteWrapper;->requery(Landroid/content/Context;Landroid/database/Cursor;)Z
-Lcom/google/android/mms/util/SqliteWrapper;->update(Landroid/content/Context;Landroid/content/ContentResolver;Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
-Lcom/google/android/mms/pdu/PduParser;->$assertionsDisabled:Z
 Lcom/google/android/util/AbstractMessageParser$Token$Type;->values()[Lcom/google/android/util/AbstractMessageParser$Token$Type;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index cb99a3a..7f597fe 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -188,57 +188,6 @@
     final ArrayMap<OnUidImportanceListener, UidObserver> mImportanceListeners = new ArrayMap<>();
 
     /**
-     * Defines acceptable types of bugreports.
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "BUGREPORT_OPTION_" }, value = {
-            BUGREPORT_OPTION_FULL,
-            BUGREPORT_OPTION_INTERACTIVE,
-            BUGREPORT_OPTION_REMOTE,
-            BUGREPORT_OPTION_WEAR,
-            BUGREPORT_OPTION_TELEPHONY,
-            BUGREPORT_OPTION_WIFI
-    })
-    public @interface BugreportMode {}
-    /**
-     * Takes a bugreport without user interference (and hence causing less
-     * interference to the system), but includes all sections.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_FULL = 0;
-    /**
-     * Allows user to monitor progress and enter additional data; might not include all
-     * sections.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_INTERACTIVE = 1;
-    /**
-     * Takes a bugreport requested remotely by administrator of the Device Owner app,
-     * not the device's user.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_REMOTE = 2;
-    /**
-     * Takes a bugreport on a wearable device.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_WEAR = 3;
-
-    /**
-     * Takes a lightweight version of bugreport that only includes a few, urgent sections
-     * used to report telephony bugs.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_TELEPHONY = 4;
-
-    /**
-     * Takes a lightweight bugreport that only includes a few sections related to Wifi.
-     * @hide
-     */
-    public static final int BUGREPORT_OPTION_WIFI = 5;
-
-    /**
      * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code
      * <meta-data>}</a> name for a 'home' Activity that declares a package that is to be
      * uninstalled in lieu of the declaring one.  The package named here must be
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1cc8499..38aac1b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4835,7 +4835,7 @@
         View.sDebugViewAttributesApplicationPackage = mCoreSettings.getString(
                 Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, "");
         String currentPackage = (mBoundApplication != null && mBoundApplication.appInfo != null)
-                ? mBoundApplication.appInfo.packageName : "";
+                ? mBoundApplication.appInfo.packageName : "<unknown-app>";
         View.sDebugViewAttributes =
                 mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0
                         || View.sDebugViewAttributesApplicationPackage.equals(currentPackage);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index e891828..b56c00e 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -29,6 +29,7 @@
 import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Matrix;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
@@ -101,6 +102,8 @@
 
     private Insets mForwardedInsets;
 
+    private float mCornerRadius;
+
     public ActivityView(Context context) {
         this(context, null /* attrs */);
     }
@@ -204,6 +207,45 @@
     }
 
     /**
+     * @hide
+     */
+    public float getCornerRadius() {
+        return mSurfaceView.getCornerRadius();
+    }
+
+    /**
+     * Control whether the surface is clipped to the same bounds as the View. If true, then
+     * the bounds set by {@link #setSurfaceClipBounds(Rect)} are applied to the surface as
+     * window-crop.
+     *
+     * @param clippingEnabled whether to enable surface clipping
+     * @hide
+     */
+    public void setSurfaceClippingEnabled(boolean clippingEnabled) {
+        mSurfaceView.setEnableSurfaceClipping(clippingEnabled);
+    }
+
+    /**
+     * Sets an area on the contained surface to which it will be clipped
+     * when it is drawn. Setting the value to null will remove the clip bounds
+     * and the surface will draw normally, using its full bounds.
+     *
+     * @param clipBounds The rectangular area, in the local coordinates of
+     * this view, to which future drawing operations will be clipped.
+     * @hide
+     */
+    public void setSurfaceClipBounds(Rect clipBounds) {
+        mSurfaceView.setClipBounds(clipBounds);
+    }
+
+    /**
+     * @hide
+     */
+    public boolean getSurfaceClipBounds(Rect outRect) {
+        return mSurfaceView.getClipBounds(outRect);
+    }
+
+    /**
      * Launch a new activity into this container.
      * <p>Activity resolved by the provided {@link Intent} must have
      * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index d74399c..a201307 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2414,14 +2414,11 @@
 
     @Override
     public Bundle getSuspendedPackageAppExtras() {
-        final PersistableBundle extras;
         try {
-            extras = mPM.getSuspendedPackageAppExtras(mContext.getOpPackageName(),
-                    getUserId());
+            return mPM.getSuspendedPackageAppExtras(mContext.getOpPackageName(), getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-        return extras != null ? new Bundle(extras.deepCopy()) : null;
     }
 
     @Override
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 8765760..b873be3 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -153,4 +153,11 @@
      * Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead.
      */
     protected abstract DevicePolicyCache getDevicePolicyCache();
+
+    /**
+     * @return cached version of device state related to DPM that can be accessed without risking
+     * deadlocks.
+     * Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead.
+     */
+    protected abstract DeviceStateCache getDeviceStateCache();
 }
diff --git a/core/java/android/app/admin/DeviceStateCache.java b/core/java/android/app/admin/DeviceStateCache.java
new file mode 100644
index 0000000..7619aa2
--- /dev/null
+++ b/core/java/android/app/admin/DeviceStateCache.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app.admin;
+
+import com.android.server.LocalServices;
+
+/**
+ * Stores a copy of the set of device state maintained by {@link DevicePolicyManager} which
+ * is not directly related to admin policies. This lives in its own class so that the state
+ * can be accessed from any place without risking dead locks.
+ *
+ * @hide
+ */
+public abstract class DeviceStateCache {
+    protected DeviceStateCache() {
+    }
+
+    /**
+     * @return the instance.
+     */
+    public static DeviceStateCache getInstance() {
+        final DevicePolicyManagerInternal dpmi =
+                LocalServices.getService(DevicePolicyManagerInternal.class);
+        return (dpmi != null) ? dpmi.getDeviceStateCache() : EmptyDeviceStateCache.INSTANCE;
+    }
+
+    /**
+     * See {@link DevicePolicyManager#isDeviceProvisioned}
+     */
+    public abstract boolean isDeviceProvisioned();
+
+    /**
+     * Empty implementation.
+     */
+    private static class EmptyDeviceStateCache extends DeviceStateCache {
+        private static final EmptyDeviceStateCache INSTANCE = new EmptyDeviceStateCache();
+
+        @Override
+        public boolean isDeviceProvisioned() {
+            return false;
+        }
+    }
+}
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index f9e710e..80c5b17 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -684,8 +684,9 @@
         static final int FLAGS_HAS_EXTRAS = 0x00400000;
         static final int FLAGS_HAS_ID = 0x00200000;
         static final int FLAGS_HAS_CHILDREN = 0x00100000;
-        static final int FLAGS_HAS_URL = 0x00080000;
+        static final int FLAGS_HAS_URL_DOMAIN = 0x00080000;
         static final int FLAGS_HAS_INPUT_TYPE = 0x00040000;
+        static final int FLAGS_HAS_URL_SCHEME = 0x00020000;
         static final int FLAGS_HAS_LOCALE_LIST = 0x00010000;
         static final int FLAGS_ALL_CONTROL = 0xfff00000;
 
@@ -829,8 +830,10 @@
             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
                 mInputType = in.readInt();
             }
-            if ((flags&FLAGS_HAS_URL) != 0) {
+            if ((flags&FLAGS_HAS_URL_SCHEME) != 0) {
                 mWebScheme = in.readString();
+            }
+            if ((flags&FLAGS_HAS_URL_DOMAIN) != 0) {
                 mWebDomain = in.readString();
             }
             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
@@ -891,8 +894,11 @@
             if (mInputType != 0) {
                 flags |= FLAGS_HAS_INPUT_TYPE;
             }
-            if (mWebScheme != null || mWebDomain != null) {
-                flags |= FLAGS_HAS_URL;
+            if (mWebScheme != null) {
+                flags |= FLAGS_HAS_URL_SCHEME;
+            }
+            if (mWebDomain != null) {
+                flags |= FLAGS_HAS_URL_DOMAIN;
             }
             if (mLocaleList != null) {
                 flags |= FLAGS_HAS_LOCALE_LIST;
@@ -1055,8 +1061,10 @@
             if ((flags&FLAGS_HAS_INPUT_TYPE) != 0) {
                 out.writeInt(mInputType);
             }
-            if ((flags&FLAGS_HAS_URL) != 0) {
+            if ((flags & FLAGS_HAS_URL_SCHEME) != 0) {
                 out.writeString(mWebScheme);
+            }
+            if ((flags&FLAGS_HAS_URL_DOMAIN) != 0) {
                 out.writeString(mWebDomain);
             }
             if ((flags&FLAGS_HAS_LOCALE_LIST) != 0) {
@@ -1431,13 +1439,18 @@
         public void setWebDomain(@Nullable String domain) {
             if (domain == null) return;
 
-            final Uri uri = Uri.parse(domain);
+            Uri uri = Uri.parse(domain);
             if (uri == null) {
                 // Cannot log domain because it could contain PII;
                 Log.w(TAG, "Failed to parse web domain");
                 return;
             }
+
             mWebScheme = uri.getScheme();
+            if (mWebScheme == null) {
+                uri = Uri.parse("http://" + domain);
+            }
+
             mWebDomain = uri.getHost();
         }
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 72204da..39ddc82 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2025,17 +2025,6 @@
     public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
 
     /**
-     * Intent extra: A {@link Bundle} of extras supplied for the launcher when any packages on
-     * device are suspended. Will be sent with {@link #ACTION_PACKAGES_SUSPENDED}.
-     *
-     * @see PackageManager#isPackageSuspended()
-     * @see #ACTION_PACKAGES_SUSPENDED
-     *
-     * @hide
-     */
-    public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
-
-    /**
      * Intent extra: ID of the shortcut used to send the share intent. Will be sent with
      * {@link #ACTION_SEND}.
      *
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c6beee2..4d7c43a 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -50,6 +50,7 @@
 import android.content.pm.dex.IArtManager;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.content.IntentSender;
@@ -280,7 +281,7 @@
 
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
-    PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId);
+    Bundle getSuspendedPackageAppExtras(String packageName, int userId);
 
     /**
      * Backup/restore support - only the system uid may use these.
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 3933e81..d2a4030 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -248,7 +248,11 @@
          *                      system, {@code null} otherwise.
          * @see PackageManager#isPackageSuspended()
          * @see #getSuspendedPackageLauncherExtras(String, UserHandle)
+         * @deprecated {@code launcherExtras} should be obtained by using
+         * {@link #getSuspendedPackageLauncherExtras(String, UserHandle)}. For all other cases,
+         * {@link #onPackagesSuspended(String[], UserHandle)} should be used.
          */
+        @Deprecated
         public void onPackagesSuspended(String[] packageNames, UserHandle user,
                 @Nullable Bundle launcherExtras) {
             onPackagesSuspended(packageNames, user);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index fafb56d..fd14d23 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -917,8 +917,9 @@
     public static final int INSTALL_DRY_RUN = 0x00800000;
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "DONT_KILL_APP" }, value = {
-            DONT_KILL_APP
+    @IntDef(flag = true, value = {
+            DONT_KILL_APP,
+            SYNCHRONOUS
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EnabledFlags {}
@@ -931,6 +932,14 @@
      */
     public static final int DONT_KILL_APP = 0x00000001;
 
+    /**
+     * Flag parameter for
+     * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
+     * that the given user's package restrictions state will be serialised to disk after the
+     * component state has been updated.
+     */
+    public static final int SYNCHRONOUS = 0x00000002;
+
     /** @hide */
     @IntDef(prefix = { "INSTALL_REASON_" }, value = {
             INSTALL_REASON_UNKNOWN,
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index f28b85c..3eef92f 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -191,11 +191,13 @@
      * suspended application.
      *
      * @param suspendedPackage The package that has been suspended.
+     * @param suspendingPackage
      * @param userId The user for which to check.
      * @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
      */
     @Nullable
-    public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId);
+    public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
+            String suspendingPackage, int userId);
 
     /**
      * Gets any distraction flags set via
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 249b691..5c74efb 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -31,6 +31,7 @@
 import android.os.BaseBundle;
 import android.os.Debug;
 import android.os.PersistableBundle;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.Slog;
@@ -38,6 +39,11 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -56,10 +62,7 @@
     public boolean hidden; // Is the app restricted by owner / admin
     public int distractionFlags;
     public boolean suspended;
-    public String suspendingPackage;
-    public SuspendDialogInfo dialogInfo;
-    public PersistableBundle suspendedAppExtras;
-    public PersistableBundle suspendedLauncherExtras;
+    public ArrayMap<String, SuspendParams> suspendParams; // Suspending package to suspend params
     public boolean instantApp;
     public boolean virtualPreload;
     public int enabled;
@@ -95,10 +98,7 @@
         hidden = o.hidden;
         distractionFlags = o.distractionFlags;
         suspended = o.suspended;
-        suspendingPackage = o.suspendingPackage;
-        dialogInfo = o.dialogInfo;
-        suspendedAppExtras = o.suspendedAppExtras;
-        suspendedLauncherExtras = o.suspendedLauncherExtras;
+        suspendParams = new ArrayMap<>(o.suspendParams);
         instantApp = o.instantApp;
         virtualPreload = o.virtualPreload;
         enabled = o.enabled;
@@ -231,19 +231,7 @@
             return false;
         }
         if (suspended) {
-            if (suspendingPackage == null
-                    || !suspendingPackage.equals(oldState.suspendingPackage)) {
-                return false;
-            }
-            if (!Objects.equals(dialogInfo, oldState.dialogInfo)) {
-                return false;
-            }
-            if (!BaseBundle.kindofEquals(suspendedAppExtras,
-                    oldState.suspendedAppExtras)) {
-                return false;
-            }
-            if (!BaseBundle.kindofEquals(suspendedLauncherExtras,
-                    oldState.suspendedLauncherExtras)) {
+            if (!Objects.equals(suspendParams, oldState.suspendParams)) {
                 return false;
             }
         }
@@ -308,4 +296,171 @@
         }
         return true;
     }
+
+    @Override
+    public int hashCode() {
+        int hashCode = Long.hashCode(ceDataInode);
+        hashCode = 31 * hashCode + Boolean.hashCode(installed);
+        hashCode = 31 * hashCode + Boolean.hashCode(stopped);
+        hashCode = 31 * hashCode + Boolean.hashCode(notLaunched);
+        hashCode = 31 * hashCode + Boolean.hashCode(hidden);
+        hashCode = 31 * hashCode + distractionFlags;
+        hashCode = 31 * hashCode + Boolean.hashCode(suspended);
+        hashCode = 31 * hashCode + Objects.hashCode(suspendParams);
+        hashCode = 31 * hashCode + Boolean.hashCode(instantApp);
+        hashCode = 31 * hashCode + Boolean.hashCode(virtualPreload);
+        hashCode = 31 * hashCode + enabled;
+        hashCode = 31 * hashCode + Objects.hashCode(lastDisableAppCaller);
+        hashCode = 31 * hashCode + domainVerificationStatus;
+        hashCode = 31 * hashCode + appLinkGeneration;
+        hashCode = 31 * hashCode + categoryHint;
+        hashCode = 31 * hashCode + installReason;
+        hashCode = 31 * hashCode + Objects.hashCode(disabledComponents);
+        hashCode = 31 * hashCode + Objects.hashCode(enabledComponents);
+        hashCode = 31 * hashCode + Objects.hashCode(harmfulAppWarning);
+        return hashCode;
+    }
+
+    /**
+     * Container to describe suspension parameters.
+     */
+    public static final class SuspendParams {
+        private static final String TAG_DIALOG_INFO = "dialog-info";
+        private static final String TAG_APP_EXTRAS = "app-extras";
+        private static final String TAG_LAUNCHER_EXTRAS = "launcher-extras";
+
+        public SuspendDialogInfo dialogInfo;
+        public PersistableBundle appExtras;
+        public PersistableBundle launcherExtras;
+
+        private SuspendParams() {
+        }
+
+        /**
+         * Returns a {@link SuspendParams} object with the given fields. Returns {@code null} if all
+         * the fields are {@code null}.
+         *
+         * @param dialogInfo
+         * @param appExtras
+         * @param launcherExtras
+         * @return A {@link SuspendParams} object or {@code null}.
+         */
+        public static SuspendParams getInstanceOrNull(SuspendDialogInfo dialogInfo,
+                PersistableBundle appExtras, PersistableBundle launcherExtras) {
+            if (dialogInfo == null && appExtras == null && launcherExtras == null) {
+                return null;
+            }
+            final SuspendParams instance = new SuspendParams();
+            instance.dialogInfo = dialogInfo;
+            instance.appExtras = appExtras;
+            instance.launcherExtras = launcherExtras;
+            return instance;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof SuspendParams)) {
+                return false;
+            }
+            final SuspendParams other = (SuspendParams) obj;
+            if (!Objects.equals(dialogInfo, other.dialogInfo)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(appExtras, other.appExtras)) {
+                return false;
+            }
+            if (!BaseBundle.kindofEquals(launcherExtras, other.launcherExtras)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int hashCode = Objects.hashCode(dialogInfo);
+            hashCode = 31 * hashCode + ((appExtras != null) ? appExtras.size() : 0);
+            hashCode = 31 * hashCode + ((launcherExtras != null) ? launcherExtras.size() : 0);
+            return hashCode;
+        }
+
+        /**
+         * Serializes this object into an xml format
+         * @param out the {@link XmlSerializer} object
+         * @throws IOException
+         */
+        public void saveToXml(XmlSerializer out) throws IOException {
+            if (dialogInfo != null) {
+                out.startTag(null, TAG_DIALOG_INFO);
+                dialogInfo.saveToXml(out);
+                out.endTag(null, TAG_DIALOG_INFO);
+            }
+            if (appExtras != null) {
+                out.startTag(null, TAG_APP_EXTRAS);
+                try {
+                    appExtras.saveToXml(out);
+                } catch (XmlPullParserException e) {
+                    Slog.e(LOG_TAG, "Exception while trying to write appExtras."
+                            + " Will be lost on reboot", e);
+                }
+                out.endTag(null, TAG_APP_EXTRAS);
+            }
+            if (launcherExtras != null) {
+                out.startTag(null, TAG_LAUNCHER_EXTRAS);
+                try {
+                    launcherExtras.saveToXml(out);
+                } catch (XmlPullParserException e) {
+                    Slog.e(LOG_TAG, "Exception while trying to write launcherExtras."
+                            + " Will be lost on reboot", e);
+                }
+                out.endTag(null, TAG_LAUNCHER_EXTRAS);
+            }
+        }
+
+        /**
+         * Parses this object from the xml format. Returns {@code null} if no object related
+         * information could be read.
+         * @param in the reader
+         * @return
+         */
+        public static SuspendParams restoreFromXml(XmlPullParser in) throws IOException {
+            SuspendDialogInfo readDialogInfo = null;
+            PersistableBundle readAppExtras = null;
+            PersistableBundle readLauncherExtras = null;
+
+            final int currentDepth = in.getDepth();
+            int type;
+            try {
+                while ((type = in.next()) != XmlPullParser.END_DOCUMENT
+                        && (type != XmlPullParser.END_TAG
+                        || in.getDepth() > currentDepth)) {
+                    if (type == XmlPullParser.END_TAG
+                            || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
+                    switch (in.getName()) {
+                        case TAG_DIALOG_INFO:
+                            readDialogInfo = SuspendDialogInfo.restoreFromXml(in);
+                            break;
+                        case TAG_APP_EXTRAS:
+                            readAppExtras = PersistableBundle.restoreFromXml(in);
+                            break;
+                        case TAG_LAUNCHER_EXTRAS:
+                            readLauncherExtras = PersistableBundle.restoreFromXml(in);
+                            break;
+                        default:
+                            Slog.w(LOG_TAG, "Unknown tag " + in.getName()
+                                    + " in SuspendParams. Ignoring");
+                            break;
+                    }
+                }
+            } catch (XmlPullParserException e) {
+                Slog.e(LOG_TAG, "Exception while trying to parse SuspendParams,"
+                        + " some fields may default", e);
+            }
+            return getInstanceOrNull(readDialogInfo, readAppExtras, readLauncherExtras);
+        }
+    }
 }
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index df652f1..0a99142 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -187,6 +187,18 @@
     @UnsupportedAppUsage
     public boolean guestToRemove;
 
+    /**
+     * This is used to optimize the creation of an user, i.e. OEMs might choose to pre-create a
+     * number of users at the first boot, so the actual creation later is faster.
+     *
+     * <p>A {@code preCreated} user is not a real user yet, so it should not show up on regular
+     * user operations (other than user creation per se).
+     *
+     * <p>Once the pre-created is used to create a "real" user later on, {@code preCreate} is set to
+     * {@code false}.
+     */
+    public boolean preCreated;
+
     @UnsupportedAppUsage
     public UserInfo(int id, String name, int flags) {
         this(id, name, null, flags);
@@ -214,6 +226,13 @@
 
     @UnsupportedAppUsage
     public boolean isGuest() {
+        return isGuest(flags);
+    }
+
+    /**
+     * Checks if the flag denotes a guest user.
+     */
+    public static boolean isGuest(@UserInfoFlag int flags) {
         return (flags & FLAG_GUEST) == FLAG_GUEST;
     }
 
@@ -224,6 +243,13 @@
 
     @UnsupportedAppUsage
     public boolean isManagedProfile() {
+        return isManagedProfile(flags);
+    }
+
+    /**
+     * Checks if the flag denotes a managed profile.
+     */
+    public static boolean isManagedProfile(@UserInfoFlag int flags) {
         return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE;
     }
 
@@ -315,6 +341,7 @@
         lastLoggedInTime = orig.lastLoggedInTime;
         lastLoggedInFingerprint = orig.lastLoggedInFingerprint;
         partial = orig.partial;
+        preCreated = orig.preCreated;
         profileGroupId = orig.profileGroupId;
         restrictedProfileParentId = orig.restrictedProfileParentId;
         guestToRemove = orig.guestToRemove;
@@ -339,6 +366,8 @@
         return "UserInfo[id=" + id
                 + ", name=" + name
                 + ", flags=" + flagsToString(flags)
+                + (preCreated ? " (pre-created)" : "")
+                + (partial ? " (partial)" : "")
                 + "]";
     }
 
@@ -362,9 +391,10 @@
         dest.writeLong(creationTime);
         dest.writeLong(lastLoggedInTime);
         dest.writeString(lastLoggedInFingerprint);
-        dest.writeInt(partial ? 1 : 0);
+        dest.writeBoolean(partial);
+        dest.writeBoolean(preCreated);
         dest.writeInt(profileGroupId);
-        dest.writeInt(guestToRemove ? 1 : 0);
+        dest.writeBoolean(guestToRemove);
         dest.writeInt(restrictedProfileParentId);
         dest.writeInt(profileBadge);
     }
@@ -389,10 +419,11 @@
         creationTime = source.readLong();
         lastLoggedInTime = source.readLong();
         lastLoggedInFingerprint = source.readString();
-        partial = source.readInt() != 0;
+        partial = source.readBoolean();
         profileGroupId = source.readInt();
-        guestToRemove = source.readInt() != 0;
+        guestToRemove = source.readBoolean();
         restrictedProfileParentId = source.readInt();
         profileBadge = source.readInt();
+        preCreated = source.readBoolean();
     }
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 2420a61..7d6dc97 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -60,7 +60,6 @@
 public final class AssetManager implements AutoCloseable {
     private static final String TAG = "AssetManager";
     private static final boolean DEBUG_REFS = false;
-    private static final boolean FEATURE_FLAG_IDMAP2 = true;
 
     private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk";
 
@@ -202,20 +201,14 @@
         try {
             final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
             apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/));
-            if (FEATURE_FLAG_IDMAP2) {
-                final String[] systemIdmapPaths =
-                    nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
-                if (systemIdmapPaths != null) {
-                    for (String idmapPath : systemIdmapPaths) {
-                        apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
-                    }
-                } else {
-                    Log.w(TAG, "'idmap2 --scan' failed: no static=\"true\" overlays targeting "
-                            + "\"android\" will be loaded");
+            final String[] systemIdmapPaths = nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
+            if (systemIdmapPaths != null) {
+                for (String idmapPath : systemIdmapPaths) {
+                    apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
                 }
             } else {
-                nativeVerifySystemIdmaps();
-                loadStaticRuntimeOverlays(apkAssets);
+                Log.w(TAG, "'idmap2 --scan' failed: no static=\"true\" overlays targeting "
+                        + "\"android\" will be loaded");
             }
 
             sSystemApkAssetsSet = new ArraySet<>(apkAssets);
@@ -1376,7 +1369,6 @@
     /**
      * @hide
      */
-    @TestApi
     @GuardedBy("this")
     public @Nullable Map<String, String> getOverlayableMap(String packageName) {
         synchronized (this) {
@@ -1385,6 +1377,18 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @TestApi
+    @GuardedBy("this")
+    public @Nullable String getOverlayablesToString(String packageName) {
+        synchronized (this) {
+            ensureValidLocked();
+            return nativeGetOverlayablesToString(mObject, packageName);
+        }
+    }
+
     @GuardedBy("this")
     private void incRefsLocked(long id) {
         if (DEBUG_REFS) {
@@ -1504,6 +1508,8 @@
     private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
     private static native @Nullable Map nativeGetOverlayableMap(long ptr,
             @NonNull String packageName);
+    private static native @Nullable String nativeGetOverlayablesToString(long ptr,
+            @NonNull String packageName);
 
     // Global debug native methods.
     /**
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 0daf30f25..638d81b 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -76,6 +76,9 @@
     // Registers a tablet mode change listener
     void registerTabletModeChangedListener(ITabletModeChangedListener listener);
 
+    // Queries whether the device's microphone is muted by switch
+    int isMicMuted();
+
     // Input device vibrator control.
     void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
     void cancelVibrate(int deviceId, IBinder token);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 2a59be2..0c0f248 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -520,6 +520,22 @@
     }
 
     /**
+     * Queries whether the device's microphone is muted
+     *
+     * @return The mic mute switch state which is one of {@link #SWITCH_STATE_UNKNOWN},
+     * {@link #SWITCH_STATE_OFF} or {@link #SWITCH_STATE_ON}.
+     * @hide
+     */
+    @SwitchState
+    public int isMicMuted() {
+        try {
+            return mIm.isMicMuted();
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets information about all supported keyboard layouts.
      * <p>
      * The input manager consults the built-in keyboard layouts as well
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 3cc2819..bc32df4 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -278,11 +278,13 @@
         /** @hide */
         public static final int OTHER_DALVIK_OTHER_ACCOUNTING = 22;
         /** @hide */
-        public static final int OTHER_DALVIK_OTHER_CODE_CACHE = 23;
+        public static final int OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE = 23;
         /** @hide */
-        public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 24;
+        public static final int OTHER_DALVIK_OTHER_APP_CODE_CACHE = 24;
         /** @hide */
-        public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 25;
+        public static final int OTHER_DALVIK_OTHER_COMPILER_METADATA = 25;
+        /** @hide */
+        public static final int OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE = 26;
         /** @hide */
         public static final int OTHER_DVK_STAT_DALVIK_OTHER_START =
                 OTHER_DALVIK_OTHER_LINEARALLOC - NUM_OTHER_STATS;
@@ -292,11 +294,11 @@
 
         // Dex subsections (Boot vdex, App dex, and App vdex).
         /** @hide */
-        public static final int OTHER_DEX_BOOT_VDEX = 26;
+        public static final int OTHER_DEX_BOOT_VDEX = 27;
         /** @hide */
-        public static final int OTHER_DEX_APP_DEX = 27;
+        public static final int OTHER_DEX_APP_DEX = 28;
         /** @hide */
-        public static final int OTHER_DEX_APP_VDEX = 28;
+        public static final int OTHER_DEX_APP_VDEX = 29;
         /** @hide */
         public static final int OTHER_DVK_STAT_DEX_START = OTHER_DEX_BOOT_VDEX - NUM_OTHER_STATS;
         /** @hide */
@@ -304,9 +306,9 @@
 
         // Art subsections (App image, boot image).
         /** @hide */
-        public static final int OTHER_ART_APP = 29;
+        public static final int OTHER_ART_APP = 30;
         /** @hide */
-        public static final int OTHER_ART_BOOT = 30;
+        public static final int OTHER_ART_BOOT = 31;
         /** @hide */
         public static final int OTHER_DVK_STAT_ART_START = OTHER_ART_APP - NUM_OTHER_STATS;
         /** @hide */
@@ -314,7 +316,7 @@
 
         /** @hide */
         @UnsupportedAppUsage
-        public static final int NUM_DVK_STATS = 14;
+        public static final int NUM_DVK_STATS = OTHER_ART_BOOT + 1 - OTHER_DALVIK_NORMAL;
 
         /** @hide */
         public static final int NUM_CATEGORIES = 9;
@@ -540,7 +542,8 @@
                 case OTHER_DALVIK_NON_MOVING: return ".NonMoving";
                 case OTHER_DALVIK_OTHER_LINEARALLOC: return ".LinearAlloc";
                 case OTHER_DALVIK_OTHER_ACCOUNTING: return ".GC";
-                case OTHER_DALVIK_OTHER_CODE_CACHE: return ".JITCache";
+                case OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE: return ".ZygoteJIT";
+                case OTHER_DALVIK_OTHER_APP_CODE_CACHE: return ".AppJIT";
                 case OTHER_DALVIK_OTHER_COMPILER_METADATA: return ".CompilerMetadata";
                 case OTHER_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE: return ".IndirectRef";
                 case OTHER_DEX_BOOT_VDEX: return ".Boot vdex";
@@ -722,7 +725,9 @@
               + getOtherPrivate(OTHER_APK)
               + getOtherPrivate(OTHER_TTF)
               + getOtherPrivate(OTHER_DEX)
-              + getOtherPrivate(OTHER_OAT);
+                + getOtherPrivate(OTHER_OAT)
+                + getOtherPrivate(OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE)
+                + getOtherPrivate(OTHER_DALVIK_OTHER_APP_CODE_CACHE);
         }
 
         /**
@@ -813,7 +818,9 @@
                 + getOtherRss(OTHER_APK)
                 + getOtherRss(OTHER_TTF)
                 + getOtherRss(OTHER_DEX)
-                + getOtherRss(OTHER_OAT);
+                + getOtherRss(OTHER_OAT)
+                + getOtherRss(OTHER_DALVIK_OTHER_ZYGOTE_CODE_CACHE)
+                + getOtherRss(OTHER_DALVIK_OTHER_APP_CODE_CACHE);
         }
 
         /**
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 9af9eda..45a9cf5 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -295,6 +295,10 @@
     /** {@hide} */
     @NonNull
     public String getTraceName(@NonNull Message message) {
+        if (message.callback instanceof TraceNameSupplier) {
+            return ((TraceNameSupplier) message.callback).getTraceName();
+        }
+
         final StringBuilder sb = new StringBuilder();
         sb.append(getClass().getName()).append(": ");
         if (message.callback != null) {
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 63641e5..ed76077 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -41,6 +41,7 @@
      */
 
     UserInfo createUser(in String name, int flags);
+    UserInfo preCreateUser(int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle,
             in String[] disallowedPackages);
     UserInfo createRestrictedProfile(String name, int parentUserHandle);
@@ -92,6 +93,7 @@
     boolean someUserHasSeedAccount(in String accountName, in String accountType);
     boolean isManagedProfile(int userId);
     boolean isDemoUser(int userId);
+    boolean isPreCreated(int userId);
     UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle,
             in String[] disallowedPackages);
     boolean isUserUnlockingOrUnlocked(int userId);
diff --git a/core/java/android/os/TraceNameSupplier.java b/core/java/android/os/TraceNameSupplier.java
new file mode 100644
index 0000000..e4b3a4e
--- /dev/null
+++ b/core/java/android/os/TraceNameSupplier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import android.annotation.NonNull;
+
+/**
+ * Supplier for custom trace messages.
+ *
+ * @hide
+ */
+public interface TraceNameSupplier {
+
+    /**
+     * Gets the name used for trace messages.
+     */
+    @NonNull String getTraceName();
+}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index af574da..7bb1cdb 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -37,6 +37,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -2013,18 +2014,20 @@
 
     /**
      * Creates a user with the specified name and options. For non-admin users, default user
-     * restrictions are going to be applied.
-     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * restrictions will be applied.
+     *
+     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param name the user's name
-     * @param flags flags that identify the type of user and other properties.
+     * @param flags UserInfo flags that identify the type of user and other properties.
      * @see UserInfo
      *
-     * @return the UserInfo object for the created user, or null if the user could not be created.
+     * @return the UserInfo object for the created user, or {@code null} if the user could not be
+     * created.
      * @hide
      */
     @UnsupportedAppUsage
-    public UserInfo createUser(String name, int flags) {
+    public @Nullable UserInfo createUser(@Nullable String name, @UserInfoFlag int flags) {
         UserInfo user = null;
         try {
             user = mService.createUser(name, flags);
@@ -2041,6 +2044,36 @@
     }
 
     /**
+     * Pre-creates a user with the specified name and options. For non-admin users, default user
+     * restrictions will be applied.
+     *
+     * <p>This method can be used by OEMs to "warm" up the user creation by pre-creating some users
+     * at the first boot, so they when the "real" user is created (for example,
+     * by {@link #createUser(String, int)} or {@link #createGuest(Context, String)}), it takes
+     * less time.
+     *
+     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param flags UserInfo flags that identify the type of user and other properties.
+     * @see UserInfo
+     *
+     * @return the UserInfo object for the created user, or {@code null} if the user could not be
+     * created.
+     *
+     * @throw {@link IllegalArgumentException} if {@code flags} contains
+     * {@link UserInfo#FLAG_MANAGED_PROFILE}.
+     *
+     * @hide
+     */
+    public @Nullable UserInfo preCreateUser(@UserInfoFlag int flags) {
+        try {
+            return mService.preCreateUser(flags);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Creates a guest user and configures it.
      * @param context an application context
      * @param name the name to set for the user
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index a5b71f6..59fb3d9 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -86,12 +86,22 @@
     public abstract void setDeviceManaged(boolean isManaged);
 
     /**
+     * Returns whether the device is managed by device owner.
+     */
+    public abstract boolean isDeviceManaged();
+
+    /**
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to update
      * whether the user is managed by profile owner.
      */
     public abstract void setUserManaged(int userId, boolean isManaged);
 
     /**
+     * whether a profile owner manages this user.
+     */
+    public abstract boolean isUserManaged(int userId);
+
+    /**
      * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to omit
      * restriction check, because DevicePolicyManager must always be able to set user icon
      * regardless of any restriction.
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 9a3a7ce..907eae8 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -758,6 +758,7 @@
                 ZygoteState state = openZygoteSocketIfNeeded(abi);
                 state.mZygoteOutputWriter.write("1\n--boot-completed\n");
                 state.mZygoteOutputWriter.flush();
+                state.mZygoteInputStream.readInt();
             }
         } catch (Exception ex) {
             throw new RuntimeException("Failed to inform zygote of boot_completed", ex);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 5b9205d..2d8af83 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -153,6 +153,11 @@
     public static final String PROP_ISOLATED_STORAGE = "persist.sys.isolated_storage";
     /** {@hide} */
     public static final String PROP_ISOLATED_STORAGE_SNAPSHOT = "sys.isolated_storage_snapshot";
+    /** {@hide} */
+    public static final String PROP_FUSE = "persist.sys.fuse";
+    /** {@hide} */
+    public static final String PROP_FUSE_SNAPSHOT = "sys.fuse_snapshot";
+
 
     /** {@hide} */
     public static final String UUID_PRIVATE_INTERNAL = null;
@@ -1575,7 +1580,14 @@
 
     /** {@hide} */
     public static boolean hasAdoptable() {
-        return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
+        switch (SystemProperties.get(PROP_ADOPTABLE)) {
+            case "force_on":
+                return true;
+            case "force_off":
+                return false;
+            default:
+                return SystemProperties.getBoolean(PROP_HAS_ADOPTABLE, false);
+        }
     }
 
     /**
diff --git a/core/java/android/os/telephony/TelephonyRegistryManager.java b/core/java/android/os/telephony/TelephonyRegistryManager.java
index 459c414..1332331 100644
--- a/core/java/android/os/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/os/telephony/TelephonyRegistryManager.java
@@ -21,23 +21,24 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataActivityType;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
+import android.telephony.Annotation.SrvccState;
 import android.telephony.CallQuality;
 import android.telephony.CellInfo;
-import android.telephony.DataFailCause;
 import android.telephony.DisconnectCause;
 import android.telephony.PhoneCapability;
-import android.telephony.PreciseCallState.State;
 import android.telephony.ServiceState;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
-import android.telephony.TelephonyManager.CallState;
-import android.telephony.TelephonyManager.DataActivityType;
-import android.telephony.TelephonyManager.DataState;
-import android.telephony.TelephonyManager.NetworkType;
-import android.telephony.TelephonyManager.RadioPowerState;
-import android.telephony.TelephonyManager.SimActivationState;
 import android.telephony.data.ApnSetting;
-import android.telephony.data.ApnSetting.ApnType;
 import android.telephony.ims.ImsReasonInfo;
 import com.android.internal.telephony.ITelephonyRegistry;
 import java.util.List;
@@ -410,7 +411,7 @@
      * @hide
      */
     public void notifyPreciseDataConnectionFailed(int subId, int slotIndex, String apnType,
-        String apn, @DataFailCause.FailCause int failCause) {
+        String apn, @DataFailureCause int failCause) {
         try {
             sRegistry.notifyPreciseDataConnectionFailed(slotIndex, subId, apnType, apn, failCause);
         } catch (RemoteException ex) {
@@ -427,7 +428,7 @@
      *
      * @hide
      */
-    public void notifySrvccStateChanged(int subId, @TelephonyManager.SrvccState int state) {
+    public void notifySrvccStateChanged(int subId, @SrvccState int state) {
         try {
             sRegistry.notifySrvccStateChanged(subId, state);
         } catch (RemoteException ex) {
@@ -464,8 +465,10 @@
      *
      * @hide
      */
-    public void notifyPreciseCallState(int subId, int slotIndex, @State int ringCallPreciseState,
-        @State int foregroundCallPreciseState, @State int backgroundCallPreciseState) {
+    public void notifyPreciseCallState(int subId, int slotIndex,
+        @PreciseCallStates int ringCallPreciseState,
+        @PreciseCallStates int foregroundCallPreciseState,
+        @PreciseCallStates int backgroundCallPreciseState) {
         try {
             sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
                 foregroundCallPreciseState, backgroundCallPreciseState);
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 2b3a2ab..4dd9bab 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -151,7 +151,7 @@
                 .PRIORITY_CATEGORY_ALARMS) != 0;
         mAllowMedia = (mNotificationPolicy.priorityCategories & NotificationManager.Policy
                 .PRIORITY_CATEGORY_MEDIA) != 0;
-        mAllowRinger = !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(
+        mAllowRinger = !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
                 mNotificationPolicy);
         mStreamType = streamType;
         mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
@@ -571,7 +571,7 @@
                         .PRIORITY_CATEGORY_ALARMS) != 0;
                 mAllowMedia = (mNotificationPolicy.priorityCategories
                         & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) != 0;
-                mAllowRinger = !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(
+                mAllowRinger = !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
                         mNotificationPolicy);
                 updateSlider();
             }
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 5e201e4..fd1381a 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -257,10 +257,20 @@
     /**
      * Namespace for storage-related features.
      *
+     * @deprecated Replace storage namespace with storage_native_boot.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    public static final String NAMESPACE_STORAGE = "storage";
+
+    /**
+     * Namespace for storage-related features, including native and boot.
+     *
      * @hide
      */
     @SystemApi
-    public static final String NAMESPACE_STORAGE = "storage";
+    public static final String NAMESPACE_STORAGE_NATIVE_BOOT = "storage_native_boot";
 
     /**
      * Namespace for System UI related features.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 61d8eb1..3c26df3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7631,6 +7631,19 @@
                 "face_unlock_always_require_confirmation";
 
         /**
+         * Whether or not a user should re enroll their face.
+         *
+         * Face unlock re enroll.
+         *  0 = No re enrollment.
+         *  1 = Re enrollment is suggested.
+         *  2 = Re enrollment is required after a set time period.
+         *  3 = Re enrollment is required immediately.
+         *
+         * @hide
+         */
+        public static final String FACE_UNLOCK_RE_ENROLL = "face_unlock_re_enroll";
+
+        /**
          * Whether or not debugging is enabled.
          * @hide
          */
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 937990f7..1f2c872 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1904,10 +1904,10 @@
     }
 
     /**
-     * Determines whether dnd behavior should mute all notification/ringer sounds
-     * (sounds associated with ringer volume discluding system)
+     * Determines whether dnd behavior should mute all ringer-controlled sounds
+     * This includes notification, ringer and system sounds
      */
-    public static boolean areAllPriorityOnlyNotificationZenSoundsMuted(NotificationManager.Policy
+    public static boolean areAllPriorityOnlyRingerSoundsMuted(NotificationManager.Policy
             policy) {
         boolean allowReminders = (policy.priorityCategories
                 & NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS) != 0;
@@ -1920,20 +1920,19 @@
         boolean allowRepeatCallers = (policy.priorityCategories
                 & NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS) != 0;
         boolean areChannelsBypassingDnd = (policy.state & Policy.STATE_CHANNELS_BYPASSING_DND) != 0;
+        boolean allowSystem =  (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
         return !allowReminders && !allowCalls && !allowMessages && !allowEvents
-                && !allowRepeatCallers && !areChannelsBypassingDnd;
+                && !allowRepeatCallers && !areChannelsBypassingDnd && !allowSystem;
     }
 
     /**
-     * Determines whether dnd behavior should mute all sounds controlled by ringer
+     * Determines whether dnd behavior should mute all sounds
      */
     public static boolean areAllZenBehaviorSoundsMuted(NotificationManager.Policy
             policy) {
         boolean allowAlarms = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS) != 0;
         boolean allowMedia = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_MEDIA) != 0;
-        boolean allowSystem = (policy.priorityCategories & Policy.PRIORITY_CATEGORY_SYSTEM) != 0;
-        return !allowAlarms && !allowMedia && !allowSystem
-                && areAllPriorityOnlyNotificationZenSoundsMuted(policy);
+        return !allowAlarms && !allowMedia && areAllPriorityOnlyRingerSoundsMuted(policy);
     }
 
     /**
@@ -1943,24 +1942,25 @@
         return zen == Global.ZEN_MODE_NO_INTERRUPTIONS
                 || zen == Global.ZEN_MODE_ALARMS
                 || (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
-                && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(consolidatedPolicy));
+                && ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(consolidatedPolicy));
     }
 
     /**
-     * Determines whether dnd behavior should mute all sounds controlled by ringer
+     * Determines whether dnd behavior should mute all ringer-controlled sounds
+     * This includes notification, ringer and system sounds
      */
-    public static boolean areAllPriorityOnlyNotificationZenSoundsMuted(ZenModeConfig config) {
+    public static boolean areAllPriorityOnlyRingerSoundsMuted(ZenModeConfig config) {
         return !config.allowReminders && !config.allowCalls && !config.allowMessages
                 && !config.allowEvents && !config.allowRepeatCallers
-                && !config.areChannelsBypassingDnd;
+                && !config.areChannelsBypassingDnd && !config.allowSystem;
     }
 
     /**
-     * Determines whether all dnd mutes all sounds
+     * Determines whether dnd mutes all sounds
      */
     public static boolean areAllZenBehaviorSoundsMuted(ZenModeConfig config) {
-        return !config.allowAlarms  && !config.allowMedia && !config.allowSystem
-                && areAllPriorityOnlyNotificationZenSoundsMuted(config);
+        return !config.allowAlarms  && !config.allowMedia
+                && areAllPriorityOnlyRingerSoundsMuted(config);
     }
 
     /**
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 5143f18..2470d19 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -58,8 +58,8 @@
  * Abstract base class for the TextClassifier service.
  *
  * <p>A TextClassifier service provides text classification related features for the system.
- * The system's default TextClassifierService is configured in
- * {@code config_defaultTextClassifierService}. If this config has no value, a
+ * The system's default TextClassifierService provider is configured in
+ * {@code config_defaultTextClassifierPackage}. If this config has no value, a
  * {@link android.view.textclassifier.TextClassifierImpl} is loaded in the calling app's process.
  *
  * <p>See: {@link TextClassifier}.
diff --git a/core/java/android/view/DragAndDropPermissions.java b/core/java/android/view/DragAndDropPermissions.java
index e72ff38..d47604d 100644
--- a/core/java/android/view/DragAndDropPermissions.java
+++ b/core/java/android/view/DragAndDropPermissions.java
@@ -37,7 +37,7 @@
  * View.startDragAndDrop} by the app that started the drag operation.
  * </p>
  * <p>
- * The life cycle of the permissions is bound to the activity used to call {@link
+ * The lifecycle of the permissions is bound to the activity used to call {@link
  * android.app.Activity#requestDragAndDropPermissions(DragEvent) requestDragAndDropPermissions}. The
  * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
  * whichever occurs first.
@@ -49,6 +49,10 @@
  * {@link Activity#onSaveInstanceState} bundle and later retrieved in order to manually release
  * the permissions once they are no longer needed.
  * </p>
+ * <p>
+ * Learn more about <a href="/guide/topics/ui/drag-drop#DragPermissionsMultiWindow">drag permissions
+ * in multi-window mode</a>.
+ * </p>
  */
 public final class DragAndDropPermissions implements Parcelable {
 
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index f34f9e6..4b872d3 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -73,6 +73,14 @@
      */
     void insetsControlChanged(in InsetsState insetsState, in InsetsSourceControl[] activeControls);
 
+    /**
+     * Called when a set of insets source window should be shown by policy.
+     *
+     * @param types internal inset types (WindowInsets.Type.InsetType) to show
+     * @param fromIme true if this request originated from IME (InputMethodService).
+     */
+    void showInsets(int types, boolean fromIme);
+
     void moved(int newX, int newY);
     void dispatchAppVisibility(boolean visible);
     void dispatchGetNewSurface();
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 49e8800..35cfe9e 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -644,4 +644,16 @@
      * Enables/disables SurfaceFlinger layer tracing.
      */
     void setLayerTracing(boolean enabled);
+
+    /**
+     * Mirrors a specified display. The root of the mirrored hierarchy will be stored in
+     * outSurfaceControl.
+     * Requires the ACCESS_SURFACE_FLINGER permission.
+     *
+     * @param displayId The id of the display to mirror
+     * @param outSurfaceControl The SurfaceControl for the root of the mirrored hierarchy.
+     *
+     * @return true if the display was successfully mirrored.
+     */
+    boolean mirrorDisplay(int displayId, out SurfaceControl outSurfaceControl);
 }
diff --git a/core/java/android/view/InputMonitor.java b/core/java/android/view/InputMonitor.java
index bbd27dc..1a1d7e6 100644
--- a/core/java/android/view/InputMonitor.java
+++ b/core/java/android/view/InputMonitor.java
@@ -21,6 +21,8 @@
 import android.os.Parcelable;
 import android.os.RemoteException;
 
+import com.android.internal.util.DataClass;
+
 /**
  * An {@code InputMonitor} allows privileged applications and components to monitor streams of
  * {@link InputEvent}s without having to be the designated recipient for the event.
@@ -31,57 +33,19 @@
  *
  * @hide
  */
+@DataClass(genToString = true)
 public final class InputMonitor implements Parcelable {
     private static final String TAG = "InputMonitor";
 
     private static final boolean DEBUG = false;
 
-    public static final Parcelable.Creator<InputMonitor> CREATOR =
-            new Parcelable.Creator<InputMonitor>() {
-
-            public InputMonitor createFromParcel(Parcel source) {
-                return new InputMonitor(source);
-            }
-
-            public InputMonitor[] newArray(int size) {
-                return new InputMonitor[size];
-            }
-    };
-
     @NonNull
     private final String mName;
     @NonNull
-    private final InputChannel mChannel;
+    private final InputChannel mInputChannel;
     @NonNull
     private final IInputMonitorHost mHost;
 
-    public InputMonitor(@NonNull String name, @NonNull InputChannel channel,
-            @NonNull IInputMonitorHost host) {
-        mName = name;
-        mChannel = channel;
-        mHost = host;
-    }
-
-    public InputMonitor(Parcel in) {
-        mName = in.readString();
-        mChannel = in.readParcelable(null);
-        mHost = IInputMonitorHost.Stub.asInterface(in.readStrongBinder());
-    }
-
-    /**
-     * Get the {@link InputChannel} corresponding to this InputMonitor
-     */
-    public InputChannel getInputChannel() {
-        return mChannel;
-    }
-
-    /**
-     * Get the name of this channel.
-     */
-    public String getName() {
-        return mName;
-    }
-
 
     /**
      * Takes all of the current pointer events streams that are currently being sent to this
@@ -107,7 +71,7 @@
      * no longer be used.
      */
     public void dispose() {
-        mChannel.dispose();
+        mInputChannel.dispose();
         try {
             mHost.dispose();
         } catch (RemoteException e) {
@@ -115,20 +79,108 @@
         }
     }
 
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mName);
-        out.writeParcelable(mChannel, flags);
-        out.writeStrongBinder(mHost.asBinder());
+
+
+    // Code below generated by codegen v1.0.1.
+    //
+    // DO NOT MODIFY!
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/InputMonitor.java
+    //
+    // CHECKSTYLE:OFF Generated code
+
+    @DataClass.Generated.Member
+    public InputMonitor(
+            @NonNull String name,
+            @NonNull InputChannel inputChannel,
+            @NonNull IInputMonitorHost host) {
+        this.mName = name;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mName);
+        this.mInputChannel = inputChannel;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mInputChannel);
+        this.mHost = host;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mHost);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull String getName() {
+        return mName;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull InputChannel getInputChannel() {
+        return mInputChannel;
+    }
+
+    @DataClass.Generated.Member
+    public @NonNull IInputMonitorHost getHost() {
+        return mHost;
     }
 
     @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
+    @DataClass.Generated.Member
     public String toString() {
-        return "InputMonitor{mName=" + mName + ", mChannel=" + mChannel + ", mHost=" + mHost + "}";
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "InputMonitor { " +
+                "name = " + mName + ", " +
+                "inputChannel = " + mInputChannel + ", " +
+                "host = " + mHost +
+        " }";
     }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeString(mName);
+        dest.writeTypedObject(mInputChannel, flags);
+        dest.writeStrongInterface(mHost);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<InputMonitor> CREATOR
+            = new Parcelable.Creator<InputMonitor>() {
+        @Override
+        public InputMonitor[] newArray(int size) {
+            return new InputMonitor[size];
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        public InputMonitor createFromParcel(Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            String name = in.readString();
+            InputChannel inputChannel = (InputChannel) in.readTypedObject(InputChannel.CREATOR);
+            IInputMonitorHost host = IInputMonitorHost.Stub.asInterface(in.readStrongBinder());
+            return new InputMonitor(
+                    name,
+                    inputChannel,
+                    host);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1569871940995L,
+            codegenVersion = "1.0.1",
+            sourceFile = "frameworks/base/core/java/android/view/InputMonitor.java",
+            inputSignatures = "private static final  java.lang.String TAG\nprivate static final  boolean DEBUG\nprivate final @android.annotation.NonNull java.lang.String mName\nprivate final @android.annotation.NonNull android.view.InputChannel mInputChannel\nprivate final @android.annotation.NonNull android.view.IInputMonitorHost mHost\npublic  void pilferPointers()\npublic  void dispose()\nclass InputMonitor extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true)")
+    @Deprecated
+    private void __metadata() {}
+
 }
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index c798d85..5a8636d 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -224,7 +224,7 @@
         show(types, false /* fromIme */);
     }
 
-    private void show(@InsetType int types, boolean fromIme) {
+    void show(@InsetType int types, boolean fromIme) {
         // TODO: Support a ResultReceiver for IME.
         // TODO(b/123718661): Make show() work for multi-session IME.
         int typesReady = 0;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index d5559aa..b685cf0 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -91,7 +91,7 @@
             boolean captureSecureLayers);
     private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken,
             long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects);
-
+    private static native long nativeMirrorSurface(long mirrorOfObject);
     private static native long nativeCreateTransaction();
     private static native long nativeGetNativeTransactionFinalizer();
     private static native void nativeApplyTransaction(long transactionObj, boolean sync);
@@ -187,8 +187,7 @@
 
     private static native void nativeSetInputWindowInfo(long transactionObj, long nativeObject,
             InputWindowHandle handle);
-    private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
-            IBinder toToken);
+
     private static native boolean nativeGetProtectedContentSupport();
     private static native void nativeSetMetadata(long transactionObj, long nativeObject, int key,
             Parcel data);
@@ -2035,6 +2034,28 @@
         return nativeSetDisplayBrightness(displayToken, brightness);
     }
 
+    /**
+     * Creates a mirrored hierarchy for the mirrorOf {@link SurfaceControl}
+     *
+     * Real Hierarchy    Mirror
+     *                     SC (value that's returned)
+     *                      |
+     *      A               A'
+     *      |               |
+     *      B               B'
+     *
+     * @param mirrorOf The root of the hierarchy that should be mirrored.
+     * @return A SurfaceControl that's the parent of the root of the mirrored hierarchy.
+     *
+     * @hide
+     */
+    public static SurfaceControl mirrorSurface(SurfaceControl mirrorOf) {
+        long nativeObj = nativeMirrorSurface(mirrorOf.mNativeObject);
+        SurfaceControl sc = new SurfaceControl();
+        sc.assignNativeObject(nativeObj);
+        return sc;
+    }
+
      /**
      * An atomic set of changes to a set of SurfaceControl.
      */
@@ -2239,22 +2260,6 @@
         }
 
         /**
-         * Transfers touch focus from one window to another. It is possible for multiple windows to
-         * have touch focus if they support split touch dispatch
-         * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
-         * method only transfers touch focus of the specified window without affecting
-         * other windows that may also have touch focus at the same time.
-         * @param fromToken The token of a window that currently has touch focus.
-         * @param toToken The token of the window that should receive touch focus in
-         * place of the first.
-         * @hide
-         */
-        public Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
-            nativeTransferTouchFocus(mNativeObject, fromToken, toToken);
-            return this;
-        }
-
-        /**
          * Waits until any changes to input windows have been sent from SurfaceFlinger to
          * InputFlinger before returning.
          *
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index db3ef20..a858300 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -167,6 +167,7 @@
 
     boolean mUseAlpha = false;
     float mSurfaceAlpha = 1f;
+    boolean mClipSurfaceToBounds;
 
     @UnsupportedAppUsage
     boolean mHaveFrame = false;
@@ -555,9 +556,52 @@
         super.dispatchDraw(canvas);
     }
 
+    /**
+     * Control whether the surface is clipped to the same bounds as the View. If true, then
+     * the bounds set by {@link #setClipBounds(Rect)} are applied to the surface as window-crop.
+     *
+     * @param enabled whether to enable surface clipping
+     * @hide
+     */
+    public void setEnableSurfaceClipping(boolean enabled) {
+        mClipSurfaceToBounds = enabled;
+        invalidate();
+    }
+
+    @Override
+    public void setClipBounds(Rect clipBounds) {
+        super.setClipBounds(clipBounds);
+
+        if (!mClipSurfaceToBounds) {
+            return;
+        }
+
+        // When cornerRadius is non-zero, a draw() is required to update
+        // the viewport (rounding the corners of the clipBounds).
+        if (mCornerRadius > 0f && !isAboveParent()) {
+            invalidate();
+        }
+
+        if (mSurfaceControl != null) {
+            if (mClipBounds != null) {
+                mTmpRect.set(mClipBounds);
+            } else {
+                mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
+            }
+            SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
+            applier.scheduleApply(
+                    new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
+                            .withWindowCrop(mTmpRect)
+                            .build());
+        }
+    }
+
     private void clearSurfaceViewPort(Canvas canvas) {
         if (mCornerRadius > 0f) {
             canvas.getClipBounds(mTmpRect);
+            if (mClipSurfaceToBounds && mClipBounds != null) {
+                mTmpRect.intersect(mClipBounds);
+            }
             canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
                     mCornerRadius, mCornerRadius, mRoundedViewportPaint);
         } else {
@@ -583,6 +627,16 @@
     }
 
     /**
+     * Returns the corner radius for the SurfaceView.
+
+     * @return the radius of the corners in pixels
+     * @hide
+     */
+    public float getCornerRadius() {
+        return mCornerRadius;
+    }
+
+    /**
      * Control whether the surface view's surface is placed on top of another
      * regular surface view in the window (but still behind the window itself).
      * This is typically used to place overlays on top of an underlying media
@@ -840,7 +894,11 @@
                             // crop the buffer to the surface size since the buffer producer may
                             // use SCALING_MODE_SCALE and submit a larger size than the surface
                             // size.
-                            mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
+                            if (mClipSurfaceToBounds && mClipBounds != null) {
+                                mSurfaceControl.setWindowCrop(mClipBounds);
+                            } else {
+                                mSurfaceControl.setWindowCrop(mSurfaceWidth, mSurfaceHeight);
+                            }
                         }
                         mSurfaceControl.setCornerRadius(mCornerRadius);
                         if (sizeChanged && !creating) {
@@ -1128,11 +1186,12 @@
                 return;
             }
 
-            if (frameNumber > 0) {
-                final ViewRootImpl viewRoot = getViewRootImpl();
-
-                mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
-                        frameNumber);
+            final ViewRootImpl viewRoot = getViewRootImpl();
+            if (frameNumber > 0 && viewRoot !=  null) {
+                if (viewRoot.mSurface.isValid()) {
+                    mRtTransaction.deferTransactionUntilSurface(mSurfaceControl, viewRoot.mSurface,
+                            frameNumber);
+                }
             }
             mRtTransaction.hide(mSurfaceControl);
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 3756a7d..fedd6fb 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -91,6 +91,7 @@
 import android.view.View.AttachInfo;
 import android.view.View.FocusDirection;
 import android.view.View.MeasureSpec;
+import android.view.WindowInsets.Type.InsetType;
 import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
@@ -4528,6 +4529,8 @@
     private static final int MSG_INSETS_CONTROL_CHANGED = 31;
     private static final int MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED = 32;
     private static final int MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED = 33;
+    private static final int MSG_SHOW_INSETS = 34;
+
 
     final class ViewRootHandler extends Handler {
         @Override
@@ -4591,6 +4594,8 @@
                     return "MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED";
                 case MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED:
                     return "MSG_LOCATION_IN_PARENT_DISPLAY_CHANGED";
+                case MSG_SHOW_INSETS:
+                    return "MSG_SHOW_INSETS";
             }
             return super.getMessageName(message);
         }
@@ -4705,6 +4710,10 @@
                     mInsetsController.onStateChanged((InsetsState) args.arg1);
                     break;
                 }
+                case MSG_SHOW_INSETS: {
+                    mInsetsController.show(msg.arg1, msg.arg2 == 1);
+                    break;
+                }
                 case MSG_WINDOW_MOVED:
                     if (mAdded) {
                         final int w = mWinFrame.width();
@@ -7484,6 +7493,10 @@
         mHandler.obtainMessage(MSG_INSETS_CONTROL_CHANGED, args).sendToTarget();
     }
 
+    private void showInsets(@InsetType int types, boolean fromIme) {
+        mHandler.obtainMessage(MSG_SHOW_INSETS, types, fromIme ? 1 : 0).sendToTarget();
+    }
+
     public void dispatchMoved(int newX, int newY) {
         if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY);
         if (mTranslator != null) {
@@ -8599,6 +8612,14 @@
         }
 
         @Override
+        public void showInsets(@InsetType int types, boolean fromIme) {
+            final ViewRootImpl viewAncestor = mViewAncestor.get();
+            if (viewAncestor != null) {
+                viewAncestor.showInsets(types, fromIme);
+            }
+        }
+
+        @Override
         public void moved(int newX, int newY) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 5f3ce33..606e8f9 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -230,6 +230,8 @@
     /**
      * Sets the identifier used to set the hint associated with this view.
      *
+     * <p>Used as metadata for fingerprinting view nodes/structures.
+     *
      * <p>Should only be set when the node is used for autofill purposes - it will be ignored
      * when used for Assist.
      */
diff --git a/core/java/android/view/WindowlessViewRoot.java b/core/java/android/view/WindowlessViewRoot.java
index b76e1fa..c2500b8 100644
--- a/core/java/android/view/WindowlessViewRoot.java
+++ b/core/java/android/view/WindowlessViewRoot.java
@@ -41,4 +41,12 @@
     public void addView(View view, WindowManager.LayoutParams attrs) {
         mViewRoot.setView(view, attrs, null);
     }
+
+    public void relayout(WindowManager.LayoutParams attrs) {
+        mViewRoot.setLayoutParams(attrs, false);
+        mViewRoot.setReportNextDraw();
+        mWm.setCompletionCallback(mViewRoot.mWindow.asBinder(), (SurfaceControl.Transaction t) -> {
+            t.apply();
+        });
+    }
 }
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 430fb6d..f4f7d0b 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -39,11 +39,27 @@
 class WindowlessWindowManager implements IWindowSession {
     private final static String TAG = "WindowlessWindowManager";
 
+    private class State {
+        SurfaceControl mSurfaceControl;
+        WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        State(SurfaceControl sc, WindowManager.LayoutParams p) {
+            mSurfaceControl = sc;
+            mParams.copyFrom(p);
+        }
+    };
     /**
      * Used to store SurfaceControl we've built for clients to
      * reconfigure them if relayout is called.
      */
-    final HashMap<IBinder, SurfaceControl> mScForWindow = new HashMap<IBinder, SurfaceControl>();
+    final HashMap<IBinder, State> mStateForWindow = new HashMap<IBinder, State>();
+
+    public interface ResizeCompleteCallback {
+        public void finished(SurfaceControl.Transaction completion);
+    }
+
+    final HashMap<IBinder, ResizeCompleteCallback> mResizeCompletionForWindow =
+        new HashMap<IBinder, ResizeCompleteCallback>();
+
     final SurfaceSession mSurfaceSession = new SurfaceSession();
     final SurfaceControl mRootSurface;
     final Configuration mConfiguration;
@@ -58,6 +74,19 @@
         mRealWm = WindowManagerGlobal.getWindowSession();
     }
 
+    /**
+     * Utility API.
+     */
+    void setCompletionCallback(IBinder window, ResizeCompleteCallback callback) {
+        if (mResizeCompletionForWindow.get(window) != null) {
+            Log.w(TAG, "Unsupported overlapping resizes");
+        }
+        mResizeCompletionForWindow.put(window, callback);
+    }
+
+    /**
+     * IWindowSession implementation.
+     */
     public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
             int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
             Rect outStableInsets, Rect outOutsets,
@@ -68,7 +97,7 @@
             .setName(attrs.getTitle().toString());
         final SurfaceControl sc = b.build();
         synchronized (this) {
-            mScForWindow.put(window.asBinder(), sc);
+            mStateForWindow.put(window.asBinder(), new State(sc, attrs));
         }
 
         if ((attrs.inputFeatures &
@@ -104,34 +133,40 @@
     }
 
     @Override
-    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
+    public int relayout(IWindow window, int seq, WindowManager.LayoutParams inAttrs,
             int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
             Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, Rect outVisibleInsets,
             Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
             DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
             SurfaceControl outSurfaceControl, InsetsState outInsetsState) {
-        SurfaceControl sc = null;
+        State state = null;
         synchronized (this) {
-            sc = mScForWindow.get(window.asBinder());
+            state = mStateForWindow.get(window.asBinder());
         }
-        if (sc == null) {
+        if (state == null) {
             throw new IllegalArgumentException(
                     "Invalid window token (never added or removed already)");
         }
+        SurfaceControl sc = state.mSurfaceControl;
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
 
+        if (inAttrs != null) {
+            state.mParams.copyFrom(inAttrs);
+        }
+        WindowManager.LayoutParams attrs = state.mParams;
+
         final Rect surfaceInsets = attrs.surfaceInsets;
         int width = surfaceInsets != null ?
-                requestedWidth + surfaceInsets.left + surfaceInsets.right : requestedWidth;
+                attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width;
         int height = surfaceInsets != null ?
-                requestedHeight + surfaceInsets.top + surfaceInsets.bottom : requestedHeight;
+                attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
 
         t.show(sc)
             .setBufferSize(sc, width, height)
             .setOpaque(sc, isOpaque(attrs))
             .apply();
         outSurfaceControl.copyFrom(sc);
-        outFrame.set(0, 0, requestedWidth, requestedHeight);
+        outFrame.set(0, 0, attrs.width, attrs.height);
 
         mergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
 
@@ -165,6 +200,17 @@
     @Override
     public void finishDrawing(android.view.IWindow window,
             android.view.SurfaceControl.Transaction postDrawTransaction) {
+        synchronized (this) {
+            final ResizeCompleteCallback c =
+                mResizeCompletionForWindow.get(window.asBinder());
+            if (c == null) {
+                // No one wanted the callback, but it wasn't necessarily unexpected.
+                postDrawTransaction.apply();
+                return;
+            }
+            c.finished(postDrawTransaction);
+            mResizeCompletionForWindow.remove(window.asBinder());
+        }
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 5e02de4..7487ec4 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -89,8 +89,13 @@
     }
 
     @Override
-    public void internalNotifySessionLifecycle(boolean started) {
-        getMainCaptureSession().notifySessionLifecycle(mId, started);
+    void internalNotifySessionResumed() {
+        getMainCaptureSession().notifySessionResumed();
+    }
+
+    @Override
+    void internalNotifySessionPaused() {
+        getMainCaptureSession().notifySessionPaused();
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index d22fac9..6040abd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -404,14 +404,14 @@
     @UiThread
     public void onActivityResumed() {
         if (mOptions.lite) return;
-        getMainContentCaptureSession().notifySessionLifecycle(/* started= */ true);
+        getMainContentCaptureSession().notifySessionResumed();
     }
 
     /** @hide */
     @UiThread
     public void onActivityPaused() {
         if (mOptions.lite) return;
-        getMainContentCaptureSession().notifySessionLifecycle(/* started= */ false);
+        getMainContentCaptureSession().notifySessionPaused();
     }
 
     /** @hide */
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index cf08c18..232d96b 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -439,17 +439,26 @@
     public abstract void internalNotifyViewTreeEvent(boolean started);
 
     /**
-     * Notifies the Content Capture Service that a session has paused/resumed.
-     *
-     * @param started whether session has resumed.
+     * Notifies the Content Capture Service that a session has resumed.
      */
-    public final void notifySessionLifecycle(boolean started) {
+    public final void notifySessionResumed() {
         if (!isContentCaptureEnabled()) return;
 
-        internalNotifySessionLifecycle(started);
+        internalNotifySessionResumed();
     }
 
-    abstract void internalNotifySessionLifecycle(boolean started);
+    abstract void internalNotifySessionResumed();
+
+    /**
+     * Notifies the Content Capture Service that a session has paused.
+     */
+    public final void notifySessionPaused() {
+        if (!isContentCaptureEnabled()) return;
+
+        internalNotifySessionPaused();
+    }
+
+    abstract void internalNotifySessionPaused();
 
     /**
      * Creates a {@link ViewStructure} for a "standard" view.
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 349ef09..96f224f 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -583,8 +583,13 @@
     }
 
     @Override
-    public void internalNotifySessionLifecycle(boolean started) {
-        notifySessionLifecycle(mId, started);
+    public void internalNotifySessionResumed() {
+        notifySessionResumed(mId);
+    }
+
+    @Override
+    public void internalNotifySessionPaused() {
+        notifySessionPaused(mId);
     }
 
     @Override
@@ -642,9 +647,12 @@
         sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
     }
 
-    void notifySessionLifecycle(int sessionId, boolean started) {
-        final int type = started ? TYPE_SESSION_RESUMED : TYPE_SESSION_PAUSED;
-        sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
+    void notifySessionResumed(int sessionId) {
+        sendEvent(new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED), FORCE_FLUSH);
+    }
+
+    void notifySessionPaused(int sessionId) {
+        sendEvent(new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED), FORCE_FLUSH);
     }
 
     void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 032af1c..6420d71 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -525,16 +525,16 @@
         final InputMethodManager fallbackImm =
                 viewRootImpl.mContext.getSystemService(InputMethodManager.class);
         if (fallbackImm == null) {
-            Log.e(TAG, "b/117267690: Failed to get non-null fallback IMM. view=" + view);
+            Log.v(TAG, "b/117267690: Failed to get non-null fallback IMM. view=" + view);
             return null;
         }
         if (fallbackImm.mDisplayId != viewRootDisplayId) {
-            Log.e(TAG, "b/117267690: Failed to get fallback IMM with expected displayId="
+            Log.v(TAG, "b/117267690: Failed to get fallback IMM with expected displayId="
                     + viewRootDisplayId + " actual IMM#displayId=" + fallbackImm.mDisplayId
                     + " view=" + view);
             return null;
         }
-        Log.w(TAG, "b/117267690: Display ID mismatch found."
+        Log.v(TAG, "b/117267690: Display ID mismatch found."
                 + " ViewRootImpl displayId=" + viewRootDisplayId
                 + " InputMethodManager displayId=" + mDisplayId
                 + ". Use the right InputMethodManager instance to avoid performance overhead.",
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 18d4d69..7282008 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -193,26 +193,24 @@
     }
 
     /**
-     * Used with {@link #setMixedContentMode}
-     *
      * In this mode, the WebView will allow a secure origin to load content from any other origin,
      * even if that origin is insecure. This is the least secure mode of operation for the WebView,
      * and where possible apps should not set this mode.
+     *
+     * @see #setMixedContentMode
      */
     public static final int MIXED_CONTENT_ALWAYS_ALLOW = 0;
 
     /**
-     * Used with {@link #setMixedContentMode}
-     *
      * In this mode, the WebView will not allow a secure origin to load content from an insecure
      * origin. This is the preferred and most secure mode of operation for the WebView and apps are
      * strongly advised to use this mode.
+     *
+     * @see #setMixedContentMode
      */
     public static final int MIXED_CONTENT_NEVER_ALLOW = 1;
 
     /**
-     * Used with {@link #setMixedContentMode}
-     *
      * In this mode, the WebView will attempt to be compatible with the approach of a modern web
      * browser with regard to mixed content. Some insecure content may be allowed to be loaded by
      * a secure origin and other types of content will be blocked. The types of content are allowed
@@ -221,6 +219,8 @@
      * This mode is intended to be used by apps that are not in control of the content that they
      * render but desire to operate in a reasonably secure environment. For highest security, apps
      * are recommended to use {@link #MIXED_CONTENT_NEVER_ALLOW}.
+     *
+     * @see #setMixedContentMode
      */
     public static final int MIXED_CONTENT_COMPATIBILITY_MODE = 2;
 
@@ -234,30 +234,30 @@
     public @interface ForceDark {}
 
     /**
-     * Used with {@link #setForceDark}
-     *
      * Disable force dark, irrespective of the force dark mode of the WebView parent. In this mode,
      * WebView content will always be rendered as-is, regardless of whether native views are being
      * automatically darkened.
+     *
+     * @see #setForceDark
      */
     public static final int FORCE_DARK_OFF = 0;
 
     /**
-     * Used with {@link #setForceDark}
-     *
      * Enable force dark dependent on the state of the WebView parent view. If the WebView parent
      * view is being automatically force darkened
      * (see: {@link android.view.View#setForceDarkAllowed}), then WebView content will be rendered
      * so as to emulate a dark theme. WebViews that are not attached to the view hierarchy will not
      * be inverted.
+     *
+     * @see #setForceDark
      */
     public static final int FORCE_DARK_AUTO = 1;
 
     /**
-     * Used with {@link #setForceDark}
-     *
      * Unconditionally enable force dark. In this mode WebView content will always be rendered so
      * as to emulate a dark theme.
+     *
+     * @see #setForceDark
      */
     public static final int FORCE_DARK_ON = 2;
 
@@ -1471,6 +1471,7 @@
      * Set the force dark mode for this WebView.
      *
      * @param forceDark the force dark mode to set.
+     * @see #getForceDark
      */
     public void setForceDark(@ForceDark int forceDark) {
         // Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
@@ -1478,10 +1479,10 @@
 
     /**
      * Get the force dark mode for this WebView.
-     *
-     * The default force dark mode is {@link #FORCE_DARK_AUTO}
+     * The default force dark mode is {@link #FORCE_DARK_AUTO}.
      *
      * @return the currently set force dark mode.
+     * @see #setForceDark
      */
     public @ForceDark int getForceDark() {
         // Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
@@ -1516,34 +1517,34 @@
     public abstract @MenuItemFlags int getDisabledActionModeMenuItems();
 
     /**
-     * Used with {@link #setDisabledActionModeMenuItems}.
-     *
      * No menu items should be disabled.
+     *
+     * @see #setDisabledActionModeMenuItems
      */
     public static final int MENU_ITEM_NONE = 0;
 
     /**
-     * Used with {@link #setDisabledActionModeMenuItems}.
-     *
      * Disable menu item "Share".
+     *
+     * @see #setDisabledActionModeMenuItems
      */
     public static final int MENU_ITEM_SHARE = 1 << 0;
 
     /**
-     * Used with {@link #setDisabledActionModeMenuItems}.
-     *
      * Disable menu item "Web Search".
+     *
+     * @see #setDisabledActionModeMenuItems
      */
     public static final int MENU_ITEM_WEB_SEARCH = 1 << 1;
 
     /**
-     * Used with {@link #setDisabledActionModeMenuItems}.
-     *
      * Disable all the action mode menu items for text processing.
      * By default WebView searches for activities that are able to handle
      * {@link android.content.Intent#ACTION_PROCESS_TEXT} and show them in the
      * action mode menu. If this flag is set via {@link
      * #setDisabledActionModeMenuItems}, these menu items will be disabled.
+     *
+     * @see #setDisabledActionModeMenuItems
      */
     public static final int MENU_ITEM_PROCESS_TEXT = 1 << 2;
 }
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 80de6fc..562cc4f 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -1103,6 +1103,7 @@
             }
 
             node.setEnabled(isDayEnabled);
+            node.setClickable(true);
 
             if (virtualViewId == mActivatedDay) {
                 // TODO: This should use activated once that's supported.
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index 5ea970d..8283eb7 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -77,10 +77,10 @@
      * @param state    of the reported change - enabled/disabled/only logged
      */
     public void reportChange(int uid, long changeId, int state) {
-        debugLog(uid, changeId, state);
         ChangeReport report = new ChangeReport(uid, changeId, state);
         synchronized (mReportedChanges) {
             if (!mReportedChanges.contains(report)) {
+                debugLog(uid, changeId, state);
                 StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId,
                         state, mSource);
                 mReportedChanges.add(report);
@@ -89,7 +89,6 @@
     }
 
     private void debugLog(int uid, long changeId, int state) {
-        //TODO(b/138374585): Implement rate limiting for the logs.
         String message = String.format("Compat change id reported: %d; UID %d; state: %s", changeId,
                 uid, stateToString(state));
         if (mSource == StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER) {
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index c928f3f..d6dcb29 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -22,11 +22,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
 import android.util.Slog;
+
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.Preconditions;
 
@@ -203,10 +203,6 @@
     public void onPackagesSuspended(String[] packages) {
     }
 
-    public void onPackagesSuspended(String[] packages, Bundle launcherExtras) {
-        onPackagesSuspended(packages);
-    }
-
     public void onPackagesUnsuspended(String[] packages) {
     }
 
@@ -446,9 +442,8 @@
             }
         } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
-            final Bundle launcherExtras = intent.getBundleExtra(Intent.EXTRA_LAUNCHER_EXTRAS);
             mSomePackagesChanged = true;
-            onPackagesSuspended(pkgList, launcherExtras);
+            onPackagesSuspended(pkgList);
         } else if (Intent.ACTION_PACKAGES_UNSUSPENDED.equals(action)) {
             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
             mSomePackagesChanged = true;
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index d6862f0..98d679e 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -32,6 +32,7 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.PrintWriter;
@@ -351,7 +352,7 @@
         @Override
         public <R> CompletionAwareJob<I, R> postForResult(@NonNull Job<I, R> job) {
             CompletionAwareJob<I, R> task = new CompletionAwareJob<>();
-            task.mDelegate = job;
+            task.mDelegate = Preconditions.checkNotNull(job);
             enqueue(task);
             return task;
         }
@@ -359,7 +360,7 @@
         @Override
         public <R> AndroidFuture<R> postAsync(@NonNull Job<I, CompletableFuture<R>> job) {
             CompletionAwareJob<I, R> task = new CompletionAwareJob<>();
-            task.mDelegate = (Job) job;
+            task.mDelegate = Preconditions.checkNotNull((Job) job);
             task.mAsync = true;
             enqueue(task);
             return task;
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 1de2e72..9fff447 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
+import android.content.type.DefaultMimeMapFactory;
 import android.os.Build;
 import android.os.DeadObjectException;
 import android.os.Debug;
@@ -33,6 +34,9 @@
 import com.android.server.NetworkManagementSocketTagger;
 import dalvik.system.RuntimeHooks;
 import dalvik.system.VMRuntime;
+
+import libcore.net.MimeMap;
+
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -192,6 +196,22 @@
         }
     }
 
+    /**
+     * Common initialization that (unlike {@link #commonInit()} should happen prior to
+     * the Zygote fork.
+     */
+    public static void preForkInit() {
+        if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
+        RuntimeInit.enableDdms();
+        /*
+         * Replace libcore's minimal default mapping between MIME types and file
+         * extensions with a mapping that's suitable for Android. Android's mapping
+         * contains many more entries that are derived from IANA registrations but
+         * with several customizations (extensions, overrides).
+         */
+        MimeMap.setDefault(DefaultMimeMapFactory.create());
+    }
+
     @UnsupportedAppUsage
     protected static final void commonInit() {
         if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
@@ -324,7 +344,7 @@
 
     @UnsupportedAppUsage
     public static final void main(String[] argv) {
-        enableDdms();
+        preForkInit();
         if (argv.length == 2 && argv[1].equals("application")) {
             if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application");
             redirectLogStreams();
@@ -418,7 +438,7 @@
     /**
      * Enable DDMS.
      */
-    static final void enableDdms() {
+    private static void enableDdms() {
         // Register handlers for DDM messages.
         android.ddm.DdmRegister.registerHandlers();
     }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index b3ec5f5..a14b093 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -306,6 +306,12 @@
     }
 
     private void handleBootCompleted() {
+        try {
+            mSocketOutStream.writeInt(0);
+        } catch (IOException ioe) {
+            throw new IllegalStateException("Error writing to command socket", ioe);
+        }
+
         VMRuntime.bootCompleted();
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3be1a1a..158700b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -847,7 +847,7 @@
             TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
                     Trace.TRACE_TAG_DALVIK);
             bootTimingsTraceLog.traceBegin("ZygoteInit");
-            RuntimeInit.enableDdms();
+            RuntimeInit.preForkInit();
 
             boolean startSystemServer = false;
             String zygoteSocketName = "zygote";
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
index 1fdb1f3..e12c031 100755
--- a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.util.function.pooled;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Message;
 import android.text.TextUtils;
@@ -527,6 +528,36 @@
         return r;
     }
 
+    // TODO: add unit test
+    @NonNull
+    private static String getFriendlyName(@NonNull Object function) {
+        // Full function has one of the following formats:
+        //   package-$$Lambda$class$randomId
+        //   package-$$Lambda$randomId
+        //
+        // We just want just package.class$Lambda (or package$Lambda) respectively
+
+        final String fullFunction = function.toString();
+
+        final int endPkgIdx = fullFunction.indexOf("-$$");
+        if (endPkgIdx == -1) return fullFunction;
+
+        // firstDollarIdx could be either beginning of class or beginning of the random id
+        final int firstDollarIdx = fullFunction.indexOf('$', endPkgIdx + 3);
+        if (firstDollarIdx == -1) return fullFunction;
+
+        final int endClassIdx = fullFunction.indexOf('$', firstDollarIdx + 1);
+        if (endClassIdx == -1) {
+            // Just package
+            return fullFunction.substring(0, endPkgIdx - 1) + "$Lambda";
+        }
+
+        // Package + class
+        return fullFunction.substring(0, endPkgIdx)
+                + fullFunction.substring(firstDollarIdx + 1, endClassIdx)
+                + "$Lambda";
+    }
+
     private static void setIfInBounds(Object[] array, int i, Object a) {
         if (i < ArrayUtils.size(array)) array[i] = a;
     }
@@ -566,6 +597,11 @@
         return this;
     }
 
+    @Override
+    public String getTraceName() {
+        return getFriendlyName(mFunc);
+    }
+
     private boolean isRecycled() {
         return (mFlags & FLAG_RECYCLED) != 0;
     }
diff --git a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
index 89ca82e..f0bc2ca 100644
--- a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
+++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.util.function.pooled;
 
+import android.os.TraceNameSupplier;
+
 import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
 
 /**
@@ -24,7 +26,8 @@
  * @see PooledLambda
  * @hide
  */
-public interface PooledRunnable extends PooledLambda, Runnable, ThrowingRunnable {
+public interface PooledRunnable
+        extends PooledLambda, Runnable, ThrowingRunnable, TraceNameSupplier {
     /** @inheritDoc */
     PooledRunnable recycleOnUse();
 }
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index cc468f4..0e078dd 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -30,6 +30,7 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.PointerIcon;
+import android.view.WindowInsets.Type.InsetType;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -75,6 +76,10 @@
     }
 
     @Override
+    public void showInsets(@InsetType int types, boolean fromIme)  throws RemoteException {
+    }
+
+    @Override
     public void moved(int newX, int newY) {
     }
 
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5a0f16e..0505fe3 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -54,6 +54,8 @@
 
     whole_static_libs: ["libandroid_graphics"],
 
+    export_static_lib_headers: ["libandroid_graphics"],
+
     shared_libs: [
         "libbase",
         "libcutils",
@@ -108,7 +110,6 @@
                 "android_view_InputEventReceiver.cpp",
                 "android_view_InputEventSender.cpp",
                 "android_view_InputQueue.cpp",
-                "android_view_FrameMetricsObserver.cpp",
                 "android_view_KeyCharacterMap.cpp",
                 "android_view_KeyEvent.cpp",
                 "android_view_MotionEvent.cpp",
@@ -337,7 +338,9 @@
     cppflags: ["-Wno-conversion-null"],
 
     srcs: [
+        "android/graphics/apex/android_bitmap.cpp",
         "android/graphics/apex/android_region.cpp",
+        "android/graphics/apex/android_paint.cpp",
 
         "android_graphics_Canvas.cpp",
         "android_graphics_ColorSpace.cpp",
@@ -390,7 +393,6 @@
     ],
 
     export_include_dirs: [
-        ".",
         "android/graphics/apex/include",
     ],
 
@@ -420,7 +422,9 @@
         android: {
             srcs: [ // sources that depend on android only libraries
                 "android/graphics/apex/android_canvas.cpp",
+                "android/graphics/apex/jni_runtime.cpp",
 
+                "android_view_FrameMetricsObserver.cpp",
                 "android_view_TextureLayer.cpp",
                 "android_view_ThreadedRenderer.cpp",
                 "android/graphics/BitmapRegionDecoder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d46fe8d..d476d2d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -22,6 +22,7 @@
 
 #include <android-base/macros.h>
 #include <android-base/properties.h>
+#include <android/graphics/jni_runtime.h>
 #include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -33,8 +34,6 @@
 #include <cutils/properties.h>
 #include <server_configurable_flags/get_flags.h>
 
-#include <SkGraphics.h>
-
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/JniInvocation.h>
@@ -56,24 +55,7 @@
 
 extern int register_android_os_Binder(JNIEnv* env);
 extern int register_android_os_Process(JNIEnv* env);
-extern int register_android_graphics_Bitmap(JNIEnv*);
-extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
-extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
-extern int register_android_graphics_Camera(JNIEnv* env);
-extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
 extern int register_android_graphics_GraphicBuffer(JNIEnv* env);
-extern int register_android_graphics_Graphics(JNIEnv* env);
-extern int register_android_graphics_ImageDecoder(JNIEnv*);
-extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv*);
-extern int register_android_graphics_Interpolator(JNIEnv* env);
-extern int register_android_graphics_MaskFilter(JNIEnv* env);
-extern int register_android_graphics_Movie(JNIEnv* env);
-extern int register_android_graphics_NinePatch(JNIEnv*);
-extern int register_android_graphics_PathEffect(JNIEnv* env);
-extern int register_android_graphics_Shader(JNIEnv* env);
-extern int register_android_graphics_Typeface(JNIEnv* env);
-extern int register_android_graphics_YuvImage(JNIEnv* env);
 
 extern int register_com_google_android_gles_jni_EGLImpl(JNIEnv* env);
 extern int register_com_google_android_gles_jni_GLImpl(JNIEnv* env);
@@ -130,46 +112,18 @@
 extern int register_android_util_StatsLogInternal(JNIEnv* env);
 extern int register_android_util_Log(JNIEnv* env);
 extern int register_android_util_MemoryIntArray(JNIEnv* env);
-extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_content_StringBlock(JNIEnv* env);
 extern int register_android_content_XmlBlock(JNIEnv* env);
 extern int register_android_content_res_ApkAssets(JNIEnv* env);
-extern int register_android_graphics_Canvas(JNIEnv* env);
-extern int register_android_graphics_CanvasProperty(JNIEnv* env);
-extern int register_android_graphics_ColorFilter(JNIEnv* env);
-extern int register_android_graphics_ColorSpace(JNIEnv* env);
-extern int register_android_graphics_DrawFilter(JNIEnv* env);
-extern int register_android_graphics_FontFamily(JNIEnv* env);
-extern int register_android_graphics_Matrix(JNIEnv* env);
-extern int register_android_graphics_Paint(JNIEnv* env);
-extern int register_android_graphics_Path(JNIEnv* env);
-extern int register_android_graphics_PathMeasure(JNIEnv* env);
-extern int register_android_graphics_Picture(JNIEnv*);
-extern int register_android_graphics_Region(JNIEnv* env);
-extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
-extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
-extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
-extern int register_android_graphics_fonts_Font(JNIEnv* env);
-extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
-extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
-extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
-extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
-extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
-extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
 extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
-extern int register_android_view_DisplayListCanvas(JNIEnv* env);
-extern int register_android_view_FrameMetricsObserver(JNIEnv* env);
 extern int register_android_view_InputApplicationHandle(JNIEnv* env);
 extern int register_android_view_InputWindowHandle(JNIEnv* env);
-extern int register_android_view_TextureLayer(JNIEnv* env);
-extern int register_android_view_RenderNode(JNIEnv* env);
 extern int register_android_view_RenderNodeAnimator(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
-extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
@@ -314,7 +268,7 @@
         mArgBlockStart(argBlockStart),
         mArgBlockLength(argBlockLength)
 {
-    SkGraphics::Init();
+    init_android_graphics();
 
     // Pre-allocate enough space to hold a fair number of options.
     mOptions.setCapacity(20);
@@ -1457,7 +1411,6 @@
     REG_JNI(register_android_util_EventLog),
     REG_JNI(register_android_util_Log),
     REG_JNI(register_android_util_MemoryIntArray),
-    REG_JNI(register_android_util_PathParser),
     REG_JNI(register_android_util_StatsLog),
     REG_JNI(register_android_util_StatsLogInternal),
     REG_JNI(register_android_app_admin_SecurityLog),
@@ -1481,20 +1434,10 @@
     REG_JNI(register_android_os_NativeHandle),
     REG_JNI(register_android_os_VintfObject),
     REG_JNI(register_android_os_VintfRuntimeInfo),
-    REG_JNI(register_android_graphics_Canvas),
-    // This needs to be before register_android_graphics_Graphics, or the latter
-    // will not be able to find the jmethodID for ColorSpace.get().
-    REG_JNI(register_android_graphics_ColorSpace),
-    REG_JNI(register_android_graphics_Graphics),
     REG_JNI(register_android_view_DisplayEventReceiver),
-    REG_JNI(register_android_view_RenderNode),
     REG_JNI(register_android_view_RenderNodeAnimator),
-    REG_JNI(register_android_view_DisplayListCanvas),
-    REG_JNI(register_android_view_FrameMetricsObserver),
     REG_JNI(register_android_view_InputApplicationHandle),
     REG_JNI(register_android_view_InputWindowHandle),
-    REG_JNI(register_android_view_TextureLayer),
-    REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
@@ -1516,43 +1459,8 @@
     REG_JNI(register_android_opengl_jni_GLES31Ext),
     REG_JNI(register_android_opengl_jni_GLES32),
 
-    REG_JNI(register_android_graphics_Bitmap),
-    REG_JNI(register_android_graphics_BitmapFactory),
-    REG_JNI(register_android_graphics_BitmapRegionDecoder),
-    REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
-    REG_JNI(register_android_graphics_Camera),
-    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
-    REG_JNI(register_android_graphics_CanvasProperty),
-    REG_JNI(register_android_graphics_ColorFilter),
-    REG_JNI(register_android_graphics_DrawFilter),
-    REG_JNI(register_android_graphics_FontFamily),
+    REG_JNI(register_android_graphics_classes),
     REG_JNI(register_android_graphics_GraphicBuffer),
-    REG_JNI(register_android_graphics_ImageDecoder),
-    REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
-    REG_JNI(register_android_graphics_Interpolator),
-    REG_JNI(register_android_graphics_MaskFilter),
-    REG_JNI(register_android_graphics_Matrix),
-    REG_JNI(register_android_graphics_Movie),
-    REG_JNI(register_android_graphics_NinePatch),
-    REG_JNI(register_android_graphics_Paint),
-    REG_JNI(register_android_graphics_Path),
-    REG_JNI(register_android_graphics_PathMeasure),
-    REG_JNI(register_android_graphics_PathEffect),
-    REG_JNI(register_android_graphics_Picture),
-    REG_JNI(register_android_graphics_Region),
-    REG_JNI(register_android_graphics_Shader),
-    REG_JNI(register_android_graphics_SurfaceTexture),
-    REG_JNI(register_android_graphics_Typeface),
-    REG_JNI(register_android_graphics_YuvImage),
-    REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
-    REG_JNI(register_android_graphics_drawable_VectorDrawable),
-    REG_JNI(register_android_graphics_fonts_Font),
-    REG_JNI(register_android_graphics_fonts_FontFamily),
-    REG_JNI(register_android_graphics_pdf_PdfDocument),
-    REG_JNI(register_android_graphics_pdf_PdfEditor),
-    REG_JNI(register_android_graphics_pdf_PdfRenderer),
-    REG_JNI(register_android_graphics_text_MeasuredText),
-    REG_JNI(register_android_graphics_text_LineBreaker),
 
     REG_JNI(register_android_database_CursorWindow),
     REG_JNI(register_android_database_SQLiteConnection),
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 06e31a1..59adbb2 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -39,8 +39,6 @@
             jobject ninePatchInsets = nullptr, int density = -1);
 
 
-void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
-
 Bitmap& toBitmap(JNIEnv* env, jobject bitmap);
 Bitmap& toBitmap(jlong bitmapHandle);
 
diff --git a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
index 173818b..d443fd8 100644
--- a/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
+++ b/core/jni/android/graphics/ByteBufferStreamAdaptor.cpp
@@ -1,6 +1,7 @@
 #include "ByteBufferStreamAdaptor.h"
 #include "core_jni_helpers.h"
 #include "Utils.h"
+#include <jni.h>
 
 #include <SkStream.h>
 
@@ -9,6 +10,24 @@
 static jmethodID gByteBuffer_getMethodID;
 static jmethodID gByteBuffer_setPositionMethodID;
 
+/**
+ * Helper method for accessing the JNI interface pointer.
+ *
+ * Image decoding (which this supports) is started on a thread that is already
+ * attached to the Java VM. But an AnimatedImageDrawable continues decoding on
+ * the AnimatedImageThread, which is not attached. This will attach if
+ * necessary.
+ */
+static JNIEnv* requireEnv(JavaVM* jvm) {
+    JNIEnv* env;
+    if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        if (jvm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+            LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+        }
+    }
+    return env;
+}
+
 class ByteBufferStream : public SkStreamAsset {
 private:
     ByteBufferStream(JavaVM* jvm, jobject jbyteBuffer, size_t initialPosition, size_t length,
@@ -46,7 +65,7 @@
     }
 
     ~ByteBufferStream() override {
-        auto* env = get_env_or_die(mJvm);
+        auto* env = requireEnv(mJvm);
         env->DeleteGlobalRef(mByteBuffer);
         env->DeleteGlobalRef(mStorage);
     }
@@ -63,7 +82,7 @@
             return this->setPosition(mPosition + size) ? size : 0;
         }
 
-        auto* env = get_env_or_die(mJvm);
+        auto* env = requireEnv(mJvm);
         size_t bytesRead = 0;
         do {
             const size_t requested = (size > kStorageSize) ? kStorageSize : size;
@@ -146,7 +165,7 @@
 
     // Range has already been checked by the caller.
     bool setPosition(size_t newPosition) {
-        auto* env = get_env_or_die(mJvm);
+        auto* env = requireEnv(mJvm);
         env->CallObjectMethod(mByteBuffer, gByteBuffer_setPositionMethodID,
                               newPosition + mInitialPosition);
         if (env->ExceptionCheck()) {
@@ -185,7 +204,7 @@
     }
 
     ~ByteArrayStream() override {
-        auto* env = get_env_or_die(mJvm);
+        auto* env = requireEnv(mJvm);
         env->DeleteGlobalRef(mByteArray);
     }
 
@@ -197,7 +216,7 @@
             return 0;
         }
 
-        auto* env = get_env_or_die(mJvm);
+        auto* env = requireEnv(mJvm);
         if (buffer) {
             env->GetByteArrayRegion(mByteArray, mPosition + mOffset, size,
                                     reinterpret_cast<jbyte*>(buffer));
diff --git a/core/jni/android/graphics/apex/TypeCast.h b/core/jni/android/graphics/apex/TypeCast.h
new file mode 100644
index 0000000..96721d0
--- /dev/null
+++ b/core/jni/android/graphics/apex/TypeCast.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_GRAPHICS_TYPECAST_H
+#define ANDROID_GRAPHICS_TYPECAST_H
+
+struct ABitmap;
+struct ACanvas;
+struct APaint;
+
+namespace android {
+
+    class Bitmap;
+    class Canvas;
+    class Paint;
+
+    class TypeCast {
+    public:
+        static inline Bitmap& toBitmapRef(const ABitmap* bitmap) {
+            return const_cast<Bitmap&>(reinterpret_cast<const Bitmap&>(*bitmap));
+        }
+
+        static inline Bitmap* toBitmap(ABitmap* bitmap) {
+            return reinterpret_cast<Bitmap*>(bitmap);
+        }
+
+        static inline ABitmap* toABitmap(Bitmap* bitmap) {
+            return reinterpret_cast<ABitmap*>(bitmap);
+        }
+
+        static inline Canvas* toCanvas(ACanvas* canvas) {
+            return reinterpret_cast<Canvas*>(canvas);
+        }
+
+        static inline ACanvas* toACanvas(Canvas* canvas) {
+            return reinterpret_cast<ACanvas *>(canvas);
+        }
+
+        static inline const Paint& toPaintRef(const APaint* paint) {
+            return reinterpret_cast<const Paint&>(*paint);
+        }
+
+        static inline const Paint* toPaint(const APaint* paint) {
+            return reinterpret_cast<const Paint*>(paint);
+        }
+
+        static inline Paint* toPaint(APaint* paint) {
+            return reinterpret_cast<Paint*>(paint);
+        }
+
+        static inline APaint* toAPaint(Paint* paint) {
+            return reinterpret_cast<APaint*>(paint);
+        }
+    };
+}; // namespace android
+
+#endif // ANDROID_GRAPHICS_TYPECAST_H
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
new file mode 100644
index 0000000..96cc5db
--- /dev/null
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+#include "android/graphics/bitmap.h"
+#include "Bitmap.h"
+#include "TypeCast.h"
+
+#include <hwui/Bitmap.h>
+
+using namespace android;
+
+ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) {
+    Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapObj);
+    bitmap.ref();
+    return TypeCast::toABitmap(&bitmap);
+}
+
+void ABitmap_acquireRef(ABitmap* bitmap) {
+    SkSafeRef(TypeCast::toBitmap(bitmap));
+}
+
+void ABitmap_releaseRef(ABitmap* bitmap) {
+    SkSafeUnref(TypeCast::toBitmap(bitmap));
+}
+
+static AndroidBitmapFormat getFormat(Bitmap* bitmap) {
+    switch (bitmap->colorType()) {
+        case kN32_SkColorType:
+            return ANDROID_BITMAP_FORMAT_RGBA_8888;
+        case kRGB_565_SkColorType:
+            return ANDROID_BITMAP_FORMAT_RGB_565;
+        case kARGB_4444_SkColorType:
+            return ANDROID_BITMAP_FORMAT_RGBA_4444;
+        case kAlpha_8_SkColorType:
+            return ANDROID_BITMAP_FORMAT_A_8;
+        case kRGBA_F16_SkColorType:
+            return ANDROID_BITMAP_FORMAT_RGBA_F16;
+        default:
+            return ANDROID_BITMAP_FORMAT_NONE;
+    }
+}
+
+static SkColorType getColorType(AndroidBitmapFormat format) {
+    switch (format) {
+        case ANDROID_BITMAP_FORMAT_RGBA_8888:
+            return kN32_SkColorType;
+        case ANDROID_BITMAP_FORMAT_RGB_565:
+            return kRGB_565_SkColorType;
+        case ANDROID_BITMAP_FORMAT_RGBA_4444:
+            return kARGB_4444_SkColorType;
+        case ANDROID_BITMAP_FORMAT_A_8:
+            return kAlpha_8_SkColorType;
+        case ANDROID_BITMAP_FORMAT_RGBA_F16:
+            return kRGBA_F16_SkColorType;
+        default:
+            return kUnknown_SkColorType;
+    }
+}
+
+ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) {
+    SkColorType dstColorType = getColorType(dstFormat);
+    if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) {
+        SkBitmap srcBitmap;
+        TypeCast::toBitmap(srcBitmapHandle)->getSkBitmap(&srcBitmap);
+
+        sk_sp<Bitmap> dstBitmap =
+                Bitmap::allocateHeapBitmap(srcBitmap.info().makeColorType(dstColorType));
+        if (dstBitmap && srcBitmap.readPixels(dstBitmap->info(), dstBitmap->pixels(),
+                                              dstBitmap->rowBytes(), 0, 0)) {
+            return TypeCast::toABitmap(dstBitmap.release());
+        }
+    }
+    return nullptr;
+}
+
+AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) {
+    Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
+
+    AndroidBitmapInfo info;
+    info.width = bitmap->width();
+    info.height = bitmap->height();
+    info.stride = bitmap->rowBytes();
+    info.format = getFormat(bitmap);
+    return info;
+}
+
+void* ABitmap_getPixels(ABitmap* bitmapHandle) {
+    Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
+    if (bitmap->isHardware()) {
+        return nullptr;
+    }
+    return bitmap->pixels();
+}
diff --git a/core/jni/android/graphics/apex/android_canvas.cpp b/core/jni/android/graphics/apex/android_canvas.cpp
index 7a4495f..527a745 100644
--- a/core/jni/android/graphics/apex/android_canvas.cpp
+++ b/core/jni/android/graphics/apex/android_canvas.cpp
@@ -16,6 +16,7 @@
 
 #include "android/graphics/canvas.h"
 
+#include "TypeCast.h"
 #include "GraphicsJNI.h"
 
 #include <hwui/Canvas.h>
@@ -25,14 +26,6 @@
 
 using namespace android;
 
-static inline Canvas* toCanvas(ACanvas* aCanvas) {
-    return reinterpret_cast<Canvas*>(aCanvas);
-}
-
-static inline ACanvas* toACanvas(Canvas* canvas) {
-    return reinterpret_cast<ACanvas*>(canvas);
-}
-
 bool ACanvas_isSupportedPixelFormat(int32_t bufferFormat) {
     ANativeWindow_Buffer buffer { 0, 0, 0, bufferFormat, nullptr, {0} };
     const SkColorType colorType = uirenderer::ANativeWindowToImageInfo(buffer, nullptr).colorType();
@@ -40,11 +33,11 @@
 }
 
 ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {
-    return toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
+    return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
 }
 
-void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
-                       int32_t /*android_dataspace_t*/ dataspace) {
+static SkBitmap convert(const ANativeWindow_Buffer* buffer,
+                        int32_t /*android_dataspace_t*/ dataspace) {
     SkBitmap bitmap;
     if (buffer != nullptr && buffer->width > 0 && buffer->height > 0) {
         sk_sp<SkColorSpace> cs(uirenderer::DataSpaceToColorSpace((android_dataspace)dataspace));
@@ -53,18 +46,44 @@
         bitmap.setInfo(imageInfo, rowBytes);
         bitmap.setPixels(buffer->bits);
     }
-
-    toCanvas(canvas)->setBitmap(bitmap);
+    return bitmap;
 }
 
-void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) {
-    //TODO update Canvas to take antialias param
-    toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-                               SkClipOp::kIntersect);
+ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
+                              int32_t /*android_dataspace_t*/ dataspace) {
+    return TypeCast::toACanvas(Canvas::create_canvas(convert(buffer, dataspace)));
 }
 
-void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool /*doAA*/) {
+void ACanvas_destroyCanvas(ACanvas* canvas) {
+    delete TypeCast::toCanvas(canvas);
+}
+
+void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
+                       int32_t /*android_dataspace_t*/ dataspace) {
+
+
+    TypeCast::toCanvas(canvas)->setBitmap(convert(buffer, dataspace));
+}
+
+void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) {
     //TODO update Canvas to take antialias param
-    toCanvas(canvas)->clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-                               SkClipOp::kDifference);
+    TypeCast::toCanvas(canvas)->clipRect(clipRect->left, clipRect->top, clipRect->right,
+                                         clipRect->bottom, SkClipOp::kIntersect);
+}
+
+void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool /*doAA*/) {
+    //TODO update Canvas to take antialias param
+    TypeCast::toCanvas(canvas)->clipRect(clipRect->left, clipRect->top, clipRect->right,
+                                         clipRect->bottom, SkClipOp::kDifference);
+}
+
+void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint) {
+    TypeCast::toCanvas(canvas)->drawRect(rect->left, rect->top, rect->right, rect->bottom,
+                                         TypeCast::toPaintRef(paint));
+}
+
+void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top,
+                        const APaint* paint) {
+    TypeCast::toCanvas(canvas)->drawBitmap(TypeCast::toBitmapRef(bitmap), left, top,
+                                           TypeCast::toPaint(paint));
 }
diff --git a/core/jni/android/graphics/apex/android_paint.cpp b/core/jni/android/graphics/apex/android_paint.cpp
new file mode 100644
index 0000000..70bd085
--- /dev/null
+++ b/core/jni/android/graphics/apex/android_paint.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#include "android/graphics/paint.h"
+
+#include "TypeCast.h"
+
+#include <hwui/Paint.h>
+
+using namespace android;
+
+
+APaint* APaint_createPaint() {
+    return TypeCast::toAPaint(new Paint());
+}
+
+void APaint_destroyPaint(APaint* paint) {
+    delete TypeCast::toPaint(paint);
+}
+
+static SkBlendMode convertBlendMode(ABlendMode blendMode) {
+    switch (blendMode) {
+        case ABLEND_MODE_CLEAR:
+            return SkBlendMode::kClear;
+        case ABLEND_MODE_SRC_OVER:
+            return SkBlendMode::kSrcOver;
+        case ABLEND_MODE_SRC:
+            return SkBlendMode::kSrc;
+    }
+}
+
+void APaint_setBlendMode(APaint* paint, ABlendMode blendMode) {
+    TypeCast::toPaint(paint)->setBlendMode(convertBlendMode(blendMode));
+}
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
new file mode 100644
index 0000000..bfa4c8d
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_GRAPHICS_BITMAP_H
+#define ANDROID_GRAPHICS_BITMAP_H
+
+#include <android/bitmap.h>
+#include <jni.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Opaque handle for a native graphics bitmap.
+ */
+typedef struct ABitmap ABitmap;
+
+ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj);
+
+ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat);
+
+void ABitmap_acquireRef(ABitmap* bitmap);
+void ABitmap_releaseRef(ABitmap* bitmap);
+
+AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap);
+
+void* ABitmap_getPixels(ABitmap* bitmap);
+
+__END_DECLS
+
+#ifdef	__cplusplus
+namespace android {
+namespace graphics {
+    class Bitmap {
+    public:
+        Bitmap() : mBitmap(nullptr) {}
+        Bitmap(JNIEnv* env, jobject bitmapObj) :
+                mBitmap(ABitmap_acquireBitmapFromJava(env, bitmapObj)) {}
+        Bitmap(const Bitmap& src) : mBitmap(src.mBitmap) { ABitmap_acquireRef(src.mBitmap); }
+        ~Bitmap() { ABitmap_releaseRef(mBitmap); }
+
+        // copy operator
+        Bitmap& operator=(const Bitmap& other) {
+            if (&other != this) {
+                ABitmap_releaseRef(mBitmap);
+                mBitmap = other.mBitmap;
+                ABitmap_acquireRef(mBitmap);
+            }
+            return *this;
+        }
+
+        // move operator
+        Bitmap& operator=(Bitmap&& other) {
+            if (&other != this) {
+                ABitmap_releaseRef(mBitmap);
+                mBitmap = other.mBitmap;
+                other.mBitmap = nullptr;
+            }
+            return *this;
+        }
+
+        Bitmap copy(AndroidBitmapFormat dstFormat) const {
+            return Bitmap(ABitmap_copy(mBitmap, dstFormat));
+        }
+
+        bool isValid() const { return mBitmap != nullptr; }
+        bool isEmpty() const {
+            AndroidBitmapInfo info = getInfo();
+            return info.width <= 0 || info.height <= 0;
+        }
+        void reset() {
+            ABitmap_releaseRef(mBitmap);
+            mBitmap = nullptr;
+        }
+
+        const ABitmap* get() const { return mBitmap; }
+
+        AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); }
+        void* getPixels() const { return ABitmap_getPixels(mBitmap); }
+    private:
+        // takes ownership of the provided ABitmap
+        Bitmap(ABitmap* bitmap) : mBitmap(bitmap) {}
+
+        ABitmap* mBitmap;
+    };
+}; // namespace graphics
+}; // namespace android
+#endif // __cplusplus
+
+#endif // ANDROID_GRAPHICS_BITMAP_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/apex/include/android/graphics/canvas.h b/core/jni/android/graphics/apex/include/android/graphics/canvas.h
index c35a7d6..190aba4 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/canvas.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/canvas.h
@@ -16,6 +16,8 @@
 #ifndef ANDROID_GRAPHICS_CANVAS_H
 #define ANDROID_GRAPHICS_CANVAS_H
 
+#include <android/graphics/bitmap.h>
+#include <android/graphics/paint.h>
 #include <android/native_window.h>
 #include <android/rect.h>
 #include <jni.h>
@@ -23,8 +25,8 @@
 __BEGIN_DECLS
 
 /**
-* Opaque handle for a native graphics canvas.
-*/
+ * Opaque handle for a native graphics canvas.
+ */
 typedef struct ACanvas ACanvas;
 
 //  One of AHardwareBuffer_Format.
@@ -33,34 +35,104 @@
 /**
  * Returns a native handle to a Java android.graphics.Canvas
  *
- * @param env
- * @param canvas
  * @return ACanvas* that is only valid for the life of the jobject.
  */
 ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvas);
 
 /**
+ * Creates a canvas that wraps the buffer
+ *
+ * @param buffer required
+ */
+ACanvas* ACanvas_createCanvas(const ANativeWindow_Buffer* buffer,
+                              int32_t /*android_dataspace_t*/ dataspace);
+
+void ACanvas_destroyCanvas(ACanvas* canvas);
+
+/**
  * Updates the canvas to render into the pixels in the provided buffer
  *
- * @param canvas
  * @param buffer The buffer that will provide the backing store for this canvas.  The buffer must
  *               remain valid until the this method is called again with either another active
  *               buffer or nullptr.  If nullptr is given the canvas will release the previous buffer
  *               and set an empty backing store.
- * @param dataspace
  */
 void ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                        int32_t /*android_dataspace_t*/ dataspace);
 
 /**
  * Clips operations on the canvas to the intersection of the current clip and the provided clipRect.
+ *
+ * @param clipRect required
  */
-void ACanvas_clipRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false);
+void ACanvas_clipRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
 
 /**
  * Clips operations on the canvas to the difference of the current clip and the provided clipRect.
+ *
+ * @param clipRect required
  */
-void ACanvas_clipOutRect(ACanvas* canvas, const ARect& clipRect, bool doAntiAlias = false);
+void ACanvas_clipOutRect(ACanvas* canvas, const ARect* clipRect, bool doAntiAlias = false);
+
+/**
+ *
+ * @param rect required
+ * @param paint required
+ */
+void ACanvas_drawRect(ACanvas* canvas, const ARect* rect, const APaint* paint);
+
+/**
+ *
+ * @param bitmap required
+ * @param left
+ * @param top
+ * @param paint
+ */
+void ACanvas_drawBitmap(ACanvas* canvas, const ABitmap* bitmap, float left, float top,
+                        const APaint* paint);
 
 __END_DECLS
+
+#ifdef	__cplusplus
+namespace android {
+namespace graphics {
+    class Canvas {
+    public:
+        Canvas(JNIEnv* env, jobject canvasObj) :
+                mCanvas(ACanvas_getNativeHandleFromJava(env, canvasObj)),
+                mOwnedPtr(false) {}
+        Canvas(const ANativeWindow_Buffer& buffer, int32_t /*android_dataspace_t*/ dataspace) :
+                mCanvas(ACanvas_createCanvas(&buffer, dataspace)),
+                mOwnedPtr(true) {}
+        ~Canvas() {
+            if (mOwnedPtr) {
+                ACanvas_destroyCanvas(mCanvas);
+            }
+        }
+
+        void setBuffer(const ANativeWindow_Buffer* buffer,
+                       int32_t /*android_dataspace_t*/ dataspace) {
+            ACanvas_setBuffer(mCanvas, buffer, dataspace);
+        }
+
+        void clipRect(const ARect& clipRect, bool doAntiAlias = false) {
+            ACanvas_clipRect(mCanvas, &clipRect, doAntiAlias);
+        }
+
+        void drawRect(const ARect& rect, const Paint& paint) {
+            ACanvas_drawRect(mCanvas, &rect, &paint.get());
+        }
+        void drawBitmap(const Bitmap& bitmap, float left, float top, const Paint* paint) {
+            const APaint* aPaint = (paint) ? &paint->get() : nullptr;
+            ACanvas_drawBitmap(mCanvas, bitmap.get(), left, top, aPaint);
+        }
+
+    private:
+        ACanvas* mCanvas;
+        const bool mOwnedPtr;
+    };
+}; // namespace graphics
+}; // namespace android
+#endif // __cplusplus
+
 #endif // ANDROID_GRAPHICS_CANVAS_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h b/core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h
new file mode 100644
index 0000000..872a949
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/jni_runtime.h
@@ -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.
+ */
+#ifndef ANDROID_GRAPHICS_JNI_RUNTIME_H
+#define ANDROID_GRAPHICS_JNI_RUNTIME_H
+
+#include <jni.h>
+
+__BEGIN_DECLS
+
+void init_android_graphics();
+
+int register_android_graphics_classes(JNIEnv* env);
+
+void zygote_preload_graphics();
+
+__END_DECLS
+
+
+#endif // ANDROID_GRAPHICS_JNI_RUNTIME_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/apex/include/android/graphics/paint.h b/core/jni/android/graphics/apex/include/android/graphics/paint.h
new file mode 100644
index 0000000..5895e00
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/paint.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+#ifndef ANDROID_GRAPHICS_PAINT_H
+#define ANDROID_GRAPHICS_PAINT_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Opaque handle for a native graphics canvas.
+ */
+typedef struct APaint APaint;
+
+/** Bitmap pixel format. */
+enum ABlendMode {
+    /** replaces destination with zero: fully transparent */
+    ABLEND_MODE_CLEAR    = 0,
+    /** source over destination */
+    ABLEND_MODE_SRC_OVER = 1,
+    /** replaces destination **/
+    ABLEND_MODE_SRC      = 2,
+};
+
+APaint* APaint_createPaint();
+
+void APaint_destroyPaint(APaint* paint);
+
+void APaint_setBlendMode(APaint* paint, ABlendMode blendMode);
+
+__END_DECLS
+
+#ifdef	__cplusplus
+namespace android {
+namespace graphics {
+    class Paint {
+    public:
+        Paint() : mPaint(APaint_createPaint()) {}
+        ~Paint() { APaint_destroyPaint(mPaint); }
+
+        void setBlendMode(ABlendMode blendMode) { APaint_setBlendMode(mPaint, blendMode); }
+
+        const APaint& get() const { return *mPaint; }
+
+    private:
+        APaint* mPaint;
+    };
+}; // namespace graphics
+}; // namespace android
+#endif // __cplusplus
+
+
+#endif // ANDROID_GRAPHICS_PAINT_H
\ No newline at end of file
diff --git a/core/jni/android/graphics/apex/jni_runtime.cpp b/core/jni/android/graphics/apex/jni_runtime.cpp
new file mode 100644
index 0000000..7f9bac0
--- /dev/null
+++ b/core/jni/android/graphics/apex/jni_runtime.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#include "android/graphics/jni_runtime.h"
+
+#include <android/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <sys/cdefs.h>
+
+#include <EGL/egl.h>
+#include <Properties.h>
+#include <SkGraphics.h>
+
+#define LOG_TAG "AndroidGraphicsJNI"
+
+extern int register_android_graphics_Bitmap(JNIEnv*);
+extern int register_android_graphics_BitmapFactory(JNIEnv*);
+extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
+extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_Camera(JNIEnv* env);
+extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
+extern int register_android_graphics_Graphics(JNIEnv* env);
+extern int register_android_graphics_ImageDecoder(JNIEnv*);
+extern int register_android_graphics_drawable_AnimatedImageDrawable(JNIEnv*);
+extern int register_android_graphics_Interpolator(JNIEnv* env);
+extern int register_android_graphics_MaskFilter(JNIEnv* env);
+extern int register_android_graphics_Movie(JNIEnv* env);
+extern int register_android_graphics_NinePatch(JNIEnv*);
+extern int register_android_graphics_PathEffect(JNIEnv* env);
+extern int register_android_graphics_Shader(JNIEnv* env);
+extern int register_android_graphics_Typeface(JNIEnv* env);
+extern int register_android_graphics_YuvImage(JNIEnv* env);
+
+namespace android {
+
+extern int register_android_graphics_Canvas(JNIEnv* env);
+extern int register_android_graphics_CanvasProperty(JNIEnv* env);
+extern int register_android_graphics_ColorFilter(JNIEnv* env);
+extern int register_android_graphics_ColorSpace(JNIEnv* env);
+extern int register_android_graphics_DrawFilter(JNIEnv* env);
+extern int register_android_graphics_FontFamily(JNIEnv* env);
+extern int register_android_graphics_Matrix(JNIEnv* env);
+extern int register_android_graphics_Paint(JNIEnv* env);
+extern int register_android_graphics_Path(JNIEnv* env);
+extern int register_android_graphics_PathMeasure(JNIEnv* env);
+extern int register_android_graphics_Picture(JNIEnv*);
+extern int register_android_graphics_Region(JNIEnv* env);
+extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
+extern int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env);
+extern int register_android_graphics_drawable_VectorDrawable(JNIEnv* env);
+extern int register_android_graphics_fonts_Font(JNIEnv* env);
+extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
+extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
+extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
+
+extern int register_android_util_PathParser(JNIEnv* env);
+extern int register_android_view_DisplayListCanvas(JNIEnv* env);
+extern int register_android_view_FrameMetricsObserver(JNIEnv* env);
+extern int register_android_view_RenderNode(JNIEnv* env);
+extern int register_android_view_TextureLayer(JNIEnv* env);
+extern int register_android_view_ThreadedRenderer(JNIEnv* env);
+
+#ifdef NDEBUG
+    #define REG_JNI(name)      { name }
+    struct RegJNIRec {
+        int (*mProc)(JNIEnv*);
+    };
+#else
+    #define REG_JNI(name)      { name, #name }
+    struct RegJNIRec {
+        int (*mProc)(JNIEnv*);
+        const char* mName;
+    };
+#endif
+
+static const RegJNIRec gRegJNI[] = {
+    REG_JNI(register_android_graphics_Canvas),
+    // This needs to be before register_android_graphics_Graphics, or the latter
+    // will not be able to find the jmethodID for ColorSpace.get().
+    REG_JNI(register_android_graphics_ColorSpace),
+    REG_JNI(register_android_graphics_Graphics),
+    REG_JNI(register_android_graphics_Bitmap),
+    REG_JNI(register_android_graphics_BitmapFactory),
+    REG_JNI(register_android_graphics_BitmapRegionDecoder),
+    REG_JNI(register_android_graphics_ByteBufferStreamAdaptor),
+    REG_JNI(register_android_graphics_Camera),
+    REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor),
+    REG_JNI(register_android_graphics_CanvasProperty),
+    REG_JNI(register_android_graphics_ColorFilter),
+    REG_JNI(register_android_graphics_DrawFilter),
+    REG_JNI(register_android_graphics_FontFamily),
+    REG_JNI(register_android_graphics_ImageDecoder),
+    REG_JNI(register_android_graphics_drawable_AnimatedImageDrawable),
+    REG_JNI(register_android_graphics_Interpolator),
+    REG_JNI(register_android_graphics_MaskFilter),
+    REG_JNI(register_android_graphics_Matrix),
+    REG_JNI(register_android_graphics_Movie),
+    REG_JNI(register_android_graphics_NinePatch),
+    REG_JNI(register_android_graphics_Paint),
+    REG_JNI(register_android_graphics_Path),
+    REG_JNI(register_android_graphics_PathMeasure),
+    REG_JNI(register_android_graphics_PathEffect),
+    REG_JNI(register_android_graphics_Picture),
+    REG_JNI(register_android_graphics_Region),
+    REG_JNI(register_android_graphics_Shader),
+    REG_JNI(register_android_graphics_SurfaceTexture),
+    REG_JNI(register_android_graphics_Typeface),
+    REG_JNI(register_android_graphics_YuvImage),
+    REG_JNI(register_android_graphics_drawable_AnimatedVectorDrawable),
+    REG_JNI(register_android_graphics_drawable_VectorDrawable),
+    REG_JNI(register_android_graphics_fonts_Font),
+    REG_JNI(register_android_graphics_fonts_FontFamily),
+    REG_JNI(register_android_graphics_pdf_PdfDocument),
+    REG_JNI(register_android_graphics_pdf_PdfEditor),
+    REG_JNI(register_android_graphics_pdf_PdfRenderer),
+    REG_JNI(register_android_graphics_text_MeasuredText),
+    REG_JNI(register_android_graphics_text_LineBreaker),
+
+    REG_JNI(register_android_util_PathParser),
+    REG_JNI(register_android_view_RenderNode),
+    REG_JNI(register_android_view_DisplayListCanvas),
+    REG_JNI(register_android_view_FrameMetricsObserver),
+    REG_JNI(register_android_view_TextureLayer),
+    REG_JNI(register_android_view_ThreadedRenderer),
+};
+
+} // namespace android
+
+void init_android_graphics() {
+    SkGraphics::Init();
+}
+
+int register_android_graphics_classes(JNIEnv *env) {
+    for (size_t i = 0; i < NELEM(android::gRegJNI); i++) {
+        if (android::gRegJNI[i].mProc(env) < 0) {
+#ifndef NDEBUG
+            __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, "JNI Error!!! %s failed to load\n",
+                                android::gRegJNI[i].mName);
+#endif
+            return -1;
+        }
+    }
+    return 0;
+}
+
+using android::uirenderer::Properties;
+using android::uirenderer::RenderPipelineType;
+
+void zygote_preload_graphics() {
+    if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    }
+}
\ No newline at end of file
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 58c5871..82601ba 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -24,15 +24,13 @@
 #include <assert.h>
 #include <dlfcn.h>
 
+#include <android/graphics/bitmap.h>
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
 #include <ETC1/etc1.h>
 
-#include <SkBitmap.h>
-
 #include "core_jni_helpers.h"
-#include "android/graphics/Bitmap.h"
 
 #undef LOG_TAG
 #define LOG_TAG "OpenGLUtil"
@@ -628,31 +626,27 @@
 
 // The internal format is no longer the same as pixel format, per Table 2 in
 // https://www.khronos.org/registry/OpenGL-Refpages/es3.1/html/glTexImage2D.xhtml
-static int checkInternalFormat(SkColorType colorType, int internalformat,
-    int type)
+static bool checkInternalFormat(int32_t bitmapFormat, int internalformat, int type)
 {
-    switch(colorType) {
-        case kN32_SkColorType:
-            return (type == GL_UNSIGNED_BYTE &&
-                    internalformat == GL_RGBA) ||
-                (type == GL_UNSIGNED_BYTE &&
-                 internalformat == GL_SRGB8_ALPHA8) ? 0 : -1;
-        case kAlpha_8_SkColorType:
-            return (type == GL_UNSIGNED_BYTE &&
-                internalformat == GL_ALPHA) ? 0 : -1;
-        case kARGB_4444_SkColorType:
-            return (type == GL_UNSIGNED_SHORT_4_4_4_4 &&
-                internalformat == GL_RGBA) ? 0 : -1;
-        case kRGB_565_SkColorType:
-            return (type == GL_UNSIGNED_SHORT_5_6_5 &&
-                internalformat == GL_RGB) ? 0 : -1;
-        case kRGBA_F16_SkColorType:
-            return (type == GL_HALF_FLOAT &&
-                internalformat == GL_RGBA16F) ? 0 : -1;
+    if (internalformat == GL_PALETTE8_RGBA8_OES) {
+        return false;
+    }
+    switch(bitmapFormat) {
+        case ANDROID_BITMAP_FORMAT_RGBA_8888:
+            return (type == GL_UNSIGNED_BYTE && internalformat == GL_RGBA) ||
+                   (type == GL_UNSIGNED_BYTE && internalformat == GL_SRGB8_ALPHA8);
+        case ANDROID_BITMAP_FORMAT_A_8:
+            return (type == GL_UNSIGNED_BYTE && internalformat == GL_ALPHA);
+        case ANDROID_BITMAP_FORMAT_RGBA_4444:
+            return (type == GL_UNSIGNED_SHORT_4_4_4_4 && internalformat == GL_RGBA);
+        case ANDROID_BITMAP_FORMAT_RGB_565:
+            return (type == GL_UNSIGNED_SHORT_5_6_5 && internalformat == GL_RGB);
+        case ANDROID_BITMAP_FORMAT_RGBA_F16:
+            return (type == GL_HALF_FLOAT && internalformat == GL_RGBA16F);
         default:
             break;
     }
-    return -1;
+    return false;
 }
 
 // The internal format is no longer the same as pixel format, per Table 2 in
@@ -670,107 +664,92 @@
     }
 }
 
-static int getInternalFormat(SkColorType colorType)
-{
-    switch(colorType) {
-        case kAlpha_8_SkColorType:
+static int getInternalFormat(int32_t bitmapFormat) {
+    switch(bitmapFormat) {
+        case ANDROID_BITMAP_FORMAT_A_8:
             return GL_ALPHA;
-        case kARGB_4444_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_4444:
             return GL_RGBA;
-        case kN32_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_8888:
             return GL_RGBA;
-        case kRGB_565_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGB_565:
             return GL_RGB;
-        case kRGBA_F16_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_F16:
             return GL_RGBA16F;
         default:
             return -1;
     }
 }
 
-static int getType(SkColorType colorType)
-{
-    switch(colorType) {
-        case kAlpha_8_SkColorType:
+static int getType(int32_t bitmapFormat) {
+    switch(bitmapFormat) {
+        case ANDROID_BITMAP_FORMAT_A_8:
             return GL_UNSIGNED_BYTE;
-        case kARGB_4444_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_4444:
             return GL_UNSIGNED_SHORT_4_4_4_4;
-        case kN32_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_8888:
             return GL_UNSIGNED_BYTE;
-        case kRGB_565_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGB_565:
             return GL_UNSIGNED_SHORT_5_6_5;
-        case kRGBA_F16_SkColorType:
+        case ANDROID_BITMAP_FORMAT_RGBA_F16:
             return GL_HALF_FLOAT;
         default:
             return -1;
     }
 }
 
-static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
-        jlong bitmapPtr)
+static jint util_getInternalFormat(JNIEnv *env, jclass clazz, jobject bitmapObj)
 {
-    SkBitmap nativeBitmap;
-    bitmap::toSkBitmap(bitmapPtr, &nativeBitmap);
-    return getInternalFormat(nativeBitmap.colorType());
+    graphics::Bitmap bitmap(env, bitmapObj);
+    return getInternalFormat(bitmap.getInfo().format);
 }
 
-static jint util_getType(JNIEnv *env, jclass clazz,
-        jlong bitmapPtr)
+static jint util_getType(JNIEnv *env, jclass clazz, jobject bitmapObj)
 {
-    SkBitmap nativeBitmap;
-    bitmap::toSkBitmap(bitmapPtr, &nativeBitmap);
-    return getType(nativeBitmap.colorType());
+    graphics::Bitmap bitmap(env, bitmapObj);
+    return getType(bitmap.getInfo().format);
 }
 
-static jint util_texImage2D(JNIEnv *env, jclass clazz,
-        jint target, jint level, jint internalformat,
-        jlong bitmapPtr, jint type, jint border)
+static jint util_texImage2D(JNIEnv *env, jclass clazz, jint target, jint level,
+        jint internalformat, jobject bitmapObj, jint type, jint border)
 {
-    SkBitmap bitmap;
-    bitmap::toSkBitmap(bitmapPtr, &bitmap);
-    SkColorType colorType = bitmap.colorType();
+    graphics::Bitmap bitmap(env, bitmapObj);
+    AndroidBitmapInfo bitmapInfo = bitmap.getInfo();
+
     if (internalformat < 0) {
-        internalformat = getInternalFormat(colorType);
+        internalformat = getInternalFormat(bitmapInfo.format);
     }
     if (type < 0) {
-        type = getType(colorType);
+        type = getType(bitmapInfo.format);
     }
-    int err = checkInternalFormat(colorType, internalformat, type);
-    if (err)
-        return err;
-    const int w = bitmap.width();
-    const int h = bitmap.height();
-    const void* p = bitmap.getPixels();
-    if (internalformat == GL_PALETTE8_RGBA8_OES) {
-        err = -1;
-    } else {
-        glTexImage2D(target, level, internalformat, w, h, border,
-                     getPixelFormatFromInternalFormat(internalformat), type, p);
+
+    if (checkInternalFormat(bitmapInfo.format, internalformat, type)) {
+        glTexImage2D(target, level, internalformat, bitmapInfo.width, bitmapInfo.height, border,
+                     getPixelFormatFromInternalFormat(internalformat), type, bitmap.getPixels());
+        return 0;
     }
-    return err;
+    return -1;
 }
 
-static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
-        jint target, jint level, jint xoffset, jint yoffset,
-        jlong bitmapPtr, jint format, jint type)
+static jint util_texSubImage2D(JNIEnv *env, jclass clazz, jint target, jint level,
+        jint xoffset, jint yoffset, jobject bitmapObj, jint format, jint type)
 {
-    SkBitmap bitmap;
-    bitmap::toSkBitmap(bitmapPtr, &bitmap);
-    SkColorType colorType = bitmap.colorType();
-    int internalFormat = getInternalFormat(colorType);
+    graphics::Bitmap bitmap(env, bitmapObj);
+    AndroidBitmapInfo bitmapInfo = bitmap.getInfo();
+
+    int internalFormat = getInternalFormat(bitmapInfo.format);
     if (format < 0) {
         format = getPixelFormatFromInternalFormat(internalFormat);
         if (format == GL_PALETTE8_RGBA8_OES)
             return -1; // glCompressedTexSubImage2D() not supported
     }
-    int err = checkInternalFormat(colorType, internalFormat, type);
-    if (err)
-        return err;
-    const int w = bitmap.width();
-    const int h = bitmap.height();
-    const void* p = bitmap.getPixels();
-    glTexSubImage2D(target, level, xoffset, yoffset, w, h, format, type, p);
-    return 0;
+
+    if (checkInternalFormat(bitmapInfo.format, internalFormat, type)) {
+        glTexSubImage2D(target, level, xoffset, yoffset, bitmapInfo.width, bitmapInfo.height,
+                        format, type, bitmap.getPixels());
+        return 0;
+    }
+    return -1;
 }
 
 /*
@@ -1036,10 +1015,10 @@
 };
 
 static const JNINativeMethod gUtilsMethods[] = {
-    { "native_getInternalFormat", "(J)I", (void*) util_getInternalFormat },
-    { "native_getType", "(J)I", (void*) util_getType },
-    { "native_texImage2D", "(IIIJII)I", (void*)util_texImage2D },
-    { "native_texSubImage2D", "(IIIIJII)I", (void*)util_texSubImage2D },
+    { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
+    { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
+    { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
+    { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
 };
 
 static const JNINativeMethod gEtc1Methods[] = {
diff --git a/core/jni/android_graphics_GraphicBuffer.cpp b/core/jni/android_graphics_GraphicBuffer.cpp
index 43d22eb..b6d5089 100644
--- a/core/jni/android_graphics_GraphicBuffer.cpp
+++ b/core/jni/android_graphics_GraphicBuffer.cpp
@@ -178,9 +178,9 @@
     nativeBuffer.format = AHardwareBuffer_convertFromPixelFormat(buffer->getPixelFormat());
     nativeBuffer.bits = bits;
 
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, &nativeBuffer, ADATASPACE_UNKNOWN);
-    ACanvas_clipRect(canvas, {rect.left, rect.top, rect.right, rect.bottom});
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(&nativeBuffer, ADATASPACE_UNKNOWN);
+    canvas.clipRect({rect.left, rect.top, rect.right, rect.bottom});
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
@@ -193,8 +193,8 @@
 static jboolean android_graphics_GraphicBuffer_unlockCanvasAndPost(JNIEnv* env, jobject,
         jlong wrapperHandle, jobject canvasObj) {
     // release the buffer from the canvas
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN);
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
 
     GraphicBufferWrapper* wrapper =
                 reinterpret_cast<GraphicBufferWrapper*>(wrapperHandle);
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index f2a4f4f..cbb74df 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -85,7 +85,8 @@
     // Dalvik other extra sections.
     HEAP_DALVIK_OTHER_LINEARALLOC,
     HEAP_DALVIK_OTHER_ACCOUNTING,
-    HEAP_DALVIK_OTHER_CODE_CACHE,
+    HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE,
+    HEAP_DALVIK_OTHER_APP_CODE_CACHE,
     HEAP_DALVIK_OTHER_COMPILER_METADATA,
     HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE,
 
@@ -282,9 +283,10 @@
             is_swappable = true;
         } else if (base::EndsWith(name, ".vdex")) {
             which_heap = HEAP_DEX;
-            // Handle system@framework@boot and system/framework/boot
+            // Handle system@framework@boot and system/framework/boot|apex
             if ((strstr(name.c_str(), "@boot") != nullptr) ||
-                    (strstr(name.c_str(), "/boot"))) {
+                    (strstr(name.c_str(), "/boot") != nullptr) ||
+                    (strstr(name.c_str(), "/apex") != nullptr)) {
                 sub_heap = HEAP_DEX_BOOT_VDEX;
             } else {
                 sub_heap = HEAP_DEX_APP_VDEX;
@@ -295,9 +297,10 @@
             is_swappable = true;
         } else if (base::EndsWith(name, ".art") || base::EndsWith(name, ".art]")) {
             which_heap = HEAP_ART;
-            // Handle system@framework@boot* and system/framework/boot*
+            // Handle system@framework@boot* and system/framework/boot|apex*
             if ((strstr(name.c_str(), "@boot") != nullptr) ||
-                    (strstr(name.c_str(), "/boot"))) {
+                    (strstr(name.c_str(), "/boot") != nullptr) ||
+                    (strstr(name.c_str(), "/apex") != nullptr)) {
                 sub_heap = HEAP_ART_BOOT;
             } else {
                 sub_heap = HEAP_ART_APP;
@@ -309,9 +312,15 @@
                 which_heap = HEAP_GL_DEV;
             } else if (base::StartsWith(name, "/dev/ashmem/CursorWindow")) {
                 which_heap = HEAP_CURSOR;
+            } else if (base::StartsWith(name, "/dev/ashmem/jit-zygote-cache")) {
+                which_heap = HEAP_DALVIK_OTHER;
+                sub_heap = HEAP_DALVIK_OTHER_ZYGOTE_CODE_CACHE;
             } else if (base::StartsWith(name, "/dev/ashmem")) {
                 which_heap = HEAP_ASHMEM;
             }
+        } else if (base::StartsWith(name, "/memfd:jit-cache")) {
+          which_heap = HEAP_DALVIK_OTHER;
+          sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE;
         } else if (base::StartsWith(name, "[anon:")) {
             which_heap = HEAP_UNKNOWN;
             if (base::StartsWith(name, "[anon:dalvik-")) {
@@ -339,7 +348,7 @@
                     sub_heap = HEAP_DALVIK_OTHER_INDIRECT_REFERENCE_TABLE;
                 } else if (base::StartsWith(name, "[anon:dalvik-jit-code-cache") ||
                         base::StartsWith(name, "[anon:dalvik-data-code-cache")) {
-                    sub_heap = HEAP_DALVIK_OTHER_CODE_CACHE;
+                    sub_heap = HEAP_DALVIK_OTHER_APP_CODE_CACHE;
                 } else if (base::StartsWith(name, "[anon:dalvik-CompilerMetadata")) {
                     sub_heap = HEAP_DALVIK_OTHER_COMPILER_METADATA;
                 } else {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index bf4ffc7..daf33f6 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -352,7 +352,7 @@
 }
 
 static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                        jstring package_name) {
+                                       jstring package_name) {
   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
   const ScopedUtfChars package_name_utf8(env, package_name);
   CHECK(package_name_utf8.c_str() != nullptr);
@@ -397,6 +397,21 @@
   return array_map;
 }
 
+static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+                                             jstring package_name) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  const ScopedUtfChars package_name_utf8(env, package_name);
+  CHECK(package_name_utf8.c_str() != nullptr);
+  const std::string std_package_name(package_name_utf8.c_str());
+
+  std::string result;
+  if (!assetmanager->GetOverlayablesToString(std_package_name, &result)) {
+    return nullptr;
+  }
+
+  return env->NewStringUTF(result.c_str());
+}
+
 #ifdef __ANDROID__ // Layoutlib does not support parcel
 static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
                                           jlongArray out_offsets) {
@@ -1608,6 +1623,8 @@
      (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
     {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
      (void*)NativeGetOverlayableMap},
+    {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
+     (void*)NativeGetOverlayablesToString},
 
     // Global management/debug methods.
     {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index c380fd5..59dab0c8 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -148,7 +148,7 @@
         mFdEvents = events;
         int fd = mInputConsumer.getChannel()->getFd();
         if (events) {
-            mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
+            mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
         } else {
             mMessageQueue->getLooper()->removeFd(fd);
         }
@@ -169,7 +169,7 @@
 
     if (events & ALOOPER_EVENT_INPUT) {
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
+        status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
         mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
         return status == OK || status == NO_MEMORY ? 1 : 0;
     }
@@ -230,7 +230,7 @@
         *outConsumedBatch = false;
     }
 
-    ScopedLocalRef<jobject> receiverObj(env, NULL);
+    ScopedLocalRef<jobject> receiverObj(env, nullptr);
     bool skipCallbacks = false;
     for (;;) {
         uint32_t seq;
@@ -305,7 +305,7 @@
 
             default:
                 assert(false); // InputConsumer should prevent this from ever happening
-                inputEventObj = NULL;
+                inputEventObj = nullptr;
             }
 
             if (inputEventObj) {
@@ -337,13 +337,13 @@
         jobject inputChannelObj, jobject messageQueueObj) {
     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
             inputChannelObj);
-    if (inputChannel == NULL) {
+    if (inputChannel == nullptr) {
         jniThrowRuntimeException(env, "InputChannel is not initialized.");
         return 0;
     }
 
     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
-    if (messageQueue == NULL) {
+    if (messageQueue == nullptr) {
         jniThrowRuntimeException(env, "MessageQueue is not initialized.");
         return 0;
     }
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 4f79790..ed2ce50 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -23,7 +23,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 #include <utils/Log.h>
-#include <android/graphics/GraphicsJNI.h>
+#include <android/graphics/bitmap.h>
 #include <nativehelper/ScopedLocalRef.h>
 
 #include "core_jni_helpers.h"
@@ -88,7 +88,7 @@
     ScopedLocalRef<jobject> bitmapObj(
             env, env->GetObjectField(pointerIconObj, gPointerIconClassInfo.mBitmap));
     if (bitmapObj.get()) {
-        GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmap));
+        outPointerIcon->bitmap = graphics::Bitmap(env, bitmapObj.get());
     }
 
     ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>(
@@ -100,7 +100,7 @@
         outPointerIcon->bitmapFrames.resize(size);
         for (jsize i = 0; i < size; ++i) {
             ScopedLocalRef<jobject> bitmapObj(env, env->GetObjectArrayElement(bitmapFramesObj.get(), i));
-            GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmapFrames[i]));
+            outPointerIcon->bitmapFrames[i] = graphics::Bitmap(env, bitmapObj.get());
         }
     }
 
diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h
index 00bdfb4..908948ea 100644
--- a/core/jni/android_view_PointerIcon.h
+++ b/core/jni/android_view_PointerIcon.h
@@ -21,8 +21,8 @@
 
 #include <vector>
 
+#include <android/graphics/bitmap.h>
 #include <utils/Errors.h>
-#include <SkBitmap.h>
 
 namespace android {
 
@@ -68,10 +68,10 @@
     }
 
     int32_t style;
-    SkBitmap bitmap;
+    graphics::Bitmap bitmap;
     float hotSpotX;
     float hotSpotY;
-    std::vector<SkBitmap> bitmapFrames;
+    std::vector<graphics::Bitmap> bitmapFrames;
     int32_t durationPerFrame;
 
     inline bool isNullIcon() {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4c2e91f..058a4c8 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -237,12 +237,11 @@
         return 0;
     }
 
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, &buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
 
     if (dirtyRectPtr) {
-        ACanvas_clipRect(canvas, {dirtyRect.left, dirtyRect.top,
-                                  dirtyRect.right, dirtyRect.bottom});
+        canvas.clipRect({dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom});
     }
 
     if (dirtyRectObj) {
@@ -268,8 +267,8 @@
     }
 
     // detach the canvas from the surface
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN);
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
 
     // unlock surface
     status_t err = surface->unlockAndPost();
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bf0f10e..d5cd278 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -458,15 +458,6 @@
     transaction->setInputWindowInfo(ctrl, *handle->getInfo());
 }
 
-static void nativeTransferTouchFocus(JNIEnv* env, jclass clazz, jlong transactionObj,
-        jobject fromTokenObj, jobject toTokenObj) {
-    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-
-    sp<IBinder> fromToken(ibinderForJavaObject(env, fromTokenObj));
-    sp<IBinder> toToken(ibinderForJavaObject(env, toTokenObj));
-    transaction->transferTouchFocus(fromToken, toToken);
-}
-
 static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
     transaction->syncInputWindows();
@@ -1253,6 +1244,15 @@
     return reinterpret_cast<jlong>(transaction.release());
 }
 
+static jlong nativeMirrorSurface(JNIEnv* env, jclass clazz, jlong mirrorOfObj) {
+    sp<SurfaceComposerClient> client = SurfaceComposerClient::getDefault();
+    SurfaceControl *mirrorOf = reinterpret_cast<SurfaceControl*>(mirrorOfObj);
+    sp<SurfaceControl> surface = client->mirrorSurface(mirrorOf);
+
+    surface->incStrong((void *)nativeCreate);
+    return reinterpret_cast<jlong>(surface.get());
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod sSurfaceControlMethods[] = {
@@ -1381,8 +1381,6 @@
             (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
             (void*)nativeSetInputWindowInfo },
-    {"nativeTransferTouchFocus", "(JLandroid/os/IBinder;Landroid/os/IBinder;)V",
-            (void*)nativeTransferTouchFocus },
     {"nativeSetMetadata", "(JJILandroid/os/Parcel;)V",
             (void*)nativeSetMetadata },
     {"nativeGetDisplayedContentSamplingAttributes",
@@ -1405,6 +1403,8 @@
             (void*)nativeReadTransactionFromParcel },
     {"nativeWriteTransactionToParcel", "(JLandroid/os/Parcel;)V",
             (void*)nativeWriteTransactionToParcel },
+    {"nativeMirrorSurface", "(J)J",
+            (void*)nativeMirrorSurface },
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 1ccb6a8..8a3f540 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -26,10 +26,7 @@
 #include <gui/GLConsumer.h>
 #include <hwui/Paint.h>
 
-#include <SkBitmap.h>
-#include <SkCanvas.h>
 #include <SkMatrix.h>
-#include <SkBlendMode.h>
 
 #include <DeferredLayerUpdater.h>
 #include <Rect.h>
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 1f69c8b..391f515 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -124,9 +124,9 @@
     int32_t status = native_window_lock(window.get(), &outBuffer, &rect);
     if (status) return JNI_FALSE;
 
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, &outBuffer, ANativeWindow_getBuffersDataSpace(window.get()));
-    ACanvas_clipRect(canvas, {rect.left, rect.top, rect.right, rect.bottom});
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(&outBuffer, ANativeWindow_getBuffersDataSpace(window.get()));
+    canvas.clipRect({rect.left, rect.top, rect.right, rect.bottom});
 
     if (dirtyRect) {
         INVOKEV(dirtyRect, gRectClassInfo.set,
@@ -140,8 +140,8 @@
         jlong nativeWindow, jobject canvasObj) {
 
     // release the buffer from the canvas
-    ACanvas* canvas = ACanvas_getNativeHandleFromJava(env, canvasObj);
-    ACanvas_setBuffer(canvas, nullptr, ADATASPACE_UNKNOWN);
+    graphics::Canvas canvas(env, canvasObj);
+    canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
 
     if (nativeWindow) {
         sp<ANativeWindow> window((ANativeWindow*) nativeWindow);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 93ef751..3516dce 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -74,7 +74,6 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <bionic/malloc.h>
-#include <cutils/ashmem.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
 #include <cutils/sockets.h>
@@ -1657,11 +1656,6 @@
   if (!SetTaskProfiles(0, {})) {
     ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
   }
-
-  /*
-   * ashmem initialization to avoid dlopen overhead
-   */
-  ashmem_init();
 }
 
 /**
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index c2a5ee43..a5152b6 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -16,17 +16,13 @@
 
 #define LOG_TAG "Zygote"
 
-#include <EGL/egl.h>
-#include <Properties.h>
+#include <android/graphics/jni_runtime.h>
 #include <ui/GraphicBufferMapper.h>
 
 #include "core_jni_helpers.h"
 
 namespace {
 
-using android::uirenderer::Properties;
-using android::uirenderer::RenderPipelineType;
-
 // Shadow call stack (SCS) is a security mitigation that uses a separate stack
 // (the SCS) for return addresses. In versions of Android newer than P, the
 // compiler cooperates with the system to ensure that the SCS address is always
@@ -64,9 +60,7 @@
 
 void android_internal_os_ZygoteInit_nativePreloadGraphicsDriver(JNIEnv* env, jclass) {
     ScopedSCSExit x;
-    if (Properties::peekRenderPipelineType() == RenderPipelineType::SkiaGL) {
-        eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    }
+    zygote_preload_graphics();
 }
 
 const JNINativeMethod gMethods[] = {
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 6ffa0c9..301fa13 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -110,7 +110,7 @@
         optional bool is_launched = 6;
         optional EnabledState enabled_state = 7;
         optional string last_disabled_app_caller = 8;
-        optional string suspending_package = 9;
+        repeated string suspending_package = 9;
         optional int32 distraction_flags = 10;
     }
 
diff --git a/core/proto/android/telecomm/enums.proto b/core/proto/android/telecomm/enums.proto
index 7a2ba62..5ca4a85 100644
--- a/core/proto/android/telecomm/enums.proto
+++ b/core/proto/android/telecomm/enums.proto
@@ -110,6 +110,24 @@
      * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}.
      */
     PULLING = 10;
+
+    /**
+     * Indicates that an incoming call has been answered by the in-call UI, but Telephony hasn't yet
+     * set the call to active.
+     */
+    ANSWERED = 11;
+
+    /**
+     * Indicates that the call is undergoing audio processing by a different app in the background.
+     * @see android.telecom.Call#STATE_AUDIO_PROCESSING
+     */
+    AUDIO_PROCESSING = 12;
+
+    /**
+     * Indicates that the call is in a fake ringing state.
+     * @see android.telecom.Call#STATE_SIMULATED_RINGING
+     */
+    SIMULATED_RINGING = 13;
 }
 
 // Disconnect causes for a call. Primarily used by android/telecom/DisconnectCause.java
diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml
index f1df2de0..37d5a411 100644
--- a/core/res/res/anim/screen_rotate_0_exit.xml
+++ b/core/res/res/anim/screen_rotate_0_exit.xml
@@ -19,7 +19,4 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:duration="@android:integer/config_shortAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml
index 1eb6361..58a1868 100644
--- a/core/res/res/anim/screen_rotate_180_exit.xml
+++ b/core/res/res/anim/screen_rotate_180_exit.xml
@@ -25,7 +25,4 @@
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
             android:duration="@android:integer/config_mediumAnimTime" />
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:interpolator="@interpolator/decelerate_cubic"
-            android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
\ No newline at end of file
diff --git a/core/res/res/anim/screen_rotate_minus_90_frame.xml b/core/res/res/anim/screen_rotate_alpha.xml
similarity index 68%
rename from core/res/res/anim/screen_rotate_minus_90_frame.xml
rename to core/res/res/anim/screen_rotate_alpha.xml
index 2d198f3..c49ef9c 100644
--- a/core/res/res/anim/screen_rotate_minus_90_frame.xml
+++ b/core/res/res/anim/screen_rotate_alpha.xml
@@ -19,10 +19,9 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:shareInterpolator="false">
-    <rotate android:fromDegrees="0" android:toDegrees="90"
-            android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:fillEnabled="true"
-            android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_longAnimTime" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+           android:interpolator="@interpolator/decelerate_quint"
+           android:fillEnabled="true"
+           android:fillBefore="true" android:fillAfter="true"
+           android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml
index 9b38939..0927dd3 100644
--- a/core/res/res/anim/screen_rotate_minus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml
@@ -40,9 +40,4 @@
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
             android:duration="@android:integer/config_mediumAnimTime" />
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:fillEnabled="true"
-            android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml
index fa34533..fd786f9 100644
--- a/core/res/res/anim/screen_rotate_plus_90_exit.xml
+++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml
@@ -40,9 +40,4 @@
             android:fillEnabled="true"
             android:fillBefore="true" android:fillAfter="true"
             android:duration="@android:integer/config_mediumAnimTime" />
-    <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:fillEnabled="true"
-            android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/screen_rotate_plus_90_frame.xml b/core/res/res/anim/screen_rotate_plus_90_frame.xml
deleted file mode 100644
index cd20050..0000000
--- a/core/res/res/anim/screen_rotate_plus_90_frame.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:shareInterpolator="false">
-    <rotate android:fromDegrees="0" android:toDegrees="-90"
-            android:pivotX="50%" android:pivotY="50%"
-            android:interpolator="@interpolator/decelerate_quint"
-            android:fillEnabled="true"
-            android:fillBefore="true" android:fillAfter="true"
-            android:duration="@android:integer/config_longAnimTime" />
-</set>
diff --git a/core/res/res/drawable-hdpi/ic_launcher_android.png b/core/res/res/drawable-hdpi/ic_launcher_android.png
index 2e9b196..8fed953 100644
--- a/core/res/res/drawable-hdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-hdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_launcher_android.png b/core/res/res/drawable-mdpi/ic_launcher_android.png
index baacd4f..16b66a1 100644
--- a/core/res/res/drawable-mdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-mdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_launcher_android.png b/core/res/res/drawable-xhdpi/ic_launcher_android.png
index 00b69a5..824794a 100644
--- a/core/res/res/drawable-xhdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-xhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_launcher_android.png b/core/res/res/drawable-xxhdpi/ic_launcher_android.png
index ad05cd5..81268b3 100644
--- a/core/res/res/drawable-xxhdpi/ic_launcher_android.png
+++ b/core/res/res/drawable-xxhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_launcher_android.png b/core/res/res/drawable-xxxhdpi/ic_launcher_android.png
new file mode 100644
index 0000000..eedc9f9
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_launcher_android.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a44b137a..0e0f34a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Laat die program toe om Moenie Steur Nie-opstelling te lees en skryf."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"begin kyk van toestemminggebruik"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Laat die houer toe om die toestemminggebruik vir \'n program te begin. Behoort nooit vir normale programme nodig te wees nie."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"toeganklikheidkortpadteiken"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Laat \'n program toe om die toeganklikheidkortpadteiken te definieer."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Beheer die lengte en die karakters wat in skermslotwagwoorde en -PIN\'e toegelaat word."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitor pogings om skerm te ontsluit"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Kies om USB-ontfouting te deaktiveer."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Toetsraamwerkmodus is geaktiveer"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Voer \'n fabriekterugstelling uit om Toetsraamwerkmodus te deaktiveer."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Reekskonsole is geaktiveer"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Werkverrigting word beïnvloed. Gaan selflaaiprogram na om te deaktiveer."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Vloeistof of vuilgoed in USB-poort"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-poort is outomaties gedeaktiveer. Tik om meer te wete te kom."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK om USB-poort te gebruik"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Ongekategoriseer"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Jy stel die belangrikheid van hierdie kennisgewings."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrik as gevolg van die mense wat betrokke is."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep (\'n gebruiker met hierdie rekening bestaan reeds)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Laat <xliff:g id="APP">%1$s</xliff:g> toe om \'n nuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> te skep?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Voeg \'n taal by"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Streekvoorkeur"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Voer taalnaam in"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index db758e3..eec1b22 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"መተግበሪያው የአትረብሽ ውቅረትን እንዲያነብብ እና እንዲጸፍ ይፈቅዳል።"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"የእይታ ፈቃድ መጠቀምን መጀመር"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ያዢው ለአንድ መተግበሪያ የፈቃድ አጠቃቀሙን እንዲያስጀምር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"የተደራሽነት አቋራጭ ዒላማ"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"መተግበሪያ የተደራሽነት አቋራጭ ዒላማን ለመግለጽ እንዲችል ይፈቅድለታል።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"በማያ ገጽ መቆለፊያ የይለፍ ቃሎች እና ፒኖች ውስጥ የሚፈቀዱ ቁምፊዎችን እና ርዝመታቸውን ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"የማሳያ-ክፈት ሙከራዎችን ክትትል ያድርጉባቸው"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ማረሚያ ላለማንቃት ምረጥ።"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"የሙከራ ጥቅል ሁነታ ነቅቷል"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"የመሞከሪያ ጥቅል ሁነታን ለማሰናከል የፋብሪካ ዳግም ቅንብርን ይሞክሩ።"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"ተከታታይ ኮንሶል ነቅቷል"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"አፈጻጸም ተጽዕኖ አርፎበታል። ለማሰናከል፣ bootloader ን ይፈትሹ።"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"በዩኤስቢ ወደብ ውስጥ ፈሳሽ ወይም ፍርስራሽ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"የዩኤስቢ ወደብ በራስ-ሰር ተሰናክሏል። የበለጠ ለመረዳት መታ ያድርጉ።"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"የዩኤስቢ ወደቡን መጠቀም ችግር የለውም"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ያልተመደቡ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"የእነዚህን ማሳወቂያዎች አስፈላጊነት አዘጋጅተዋል።"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ይሄ በሚሳተፉ ሰዎች ምክንያት አስፈላጊ ነው።"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> በ<xliff:g id="ACCOUNT">%2$s</xliff:g> አዲስ ተጠቃሚ እንዲፈጥር ይፈቀድለት (ይህ መለያ ያለው ተጠቃሚ አስቀድሞ አለ)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> አዲስ ተጠቃሚ ከ <xliff:g id="ACCOUNT">%2$s</xliff:g> ጋር መፍጠር እንዲችል ይፍቀዱ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ቋንቋ ያክሉ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"የክልል ምርጫ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"የቋንቋ ስም ይተይቡ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 113a342..d195d74 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -536,7 +536,7 @@
     <string name="permdesc_imagesWrite" msgid="7073662756617474375">"للسماح للتطبيق بتعديل مجموعة صورك."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"قراءة المواقع من مجموعة الوسائط التابعة لك"</string>
     <string name="permdesc_mediaLocation" msgid="2237023389178865130">"للسماح للتطبيق بقراءة المواقع من مجموعة الوسائط التابعة لك."</string>
-    <string name="biometric_dialog_default_title" msgid="881952973720613213">"التحقق من هويتك"</string>
+    <string name="biometric_dialog_default_title" msgid="881952973720613213">"إثبات هويتك"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"معدّات المقاييس الحيوية غير متاحة."</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"تم إلغاء المصادقة."</string>
     <string name="biometric_not_recognized" msgid="5770511773560736082">"لم يتم التعرف عليها."</string>
@@ -667,6 +667,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"للسماح للتطبيق بقراءة تهيئة \"عدم الإزعاج\" وكتابتها."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"بدء استخدام إذن العرض"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"للسماح للمالك ببدء استخدام الإذن لأحد التطبيقات. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"هدف اختصار أدوات تمكين الوصول"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"للسماح للتطبيق بتحديد هدف اختصار أدوات تمكين الوصول."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"للتحكم في الطول والأحرف المسموح بها في كلمات المرور وأرقام التعريف الشخصي في قفل الشاشة."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -1449,6 +1451,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏اختيار إيقاف تصحيح أخطاء USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"تم تفعيل وضع \"مفعّل الاختبار\""</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"يمكنك إجراء إعادة ضبط على إعدادات المصنع لإيقاف وضع \"مفعِّل اختبار\"."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"وحدة التحكّم التسلسلية مفعّلة"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"الأداء متأثر. لإيقاف وحدة التحكّم، تحقّق من برنامج الإقلاع."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"‏السوائل والشوائب في منفذ USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"‏تمّ إيقاف منفذ USB تلقائيًا. انقُر لمعرفة المزيد من المعلومات."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"‏مسموح باستخدام منفذ USB"</string>
@@ -2026,10 +2030,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"غير مصنفة"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"لقد عيَّنت أهمية هذه الإشعارات."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"هذه الرسالة مهمة نظرًا لأهمية الأشخاص المعنيين."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> (يوجد مستخدم بهذا الحساب مسبقًا)؟"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"هل تسمح لتطبيق <xliff:g id="APP">%1$s</xliff:g> بإنشاء مستخدم جديد باستخدام <xliff:g id="ACCOUNT">%2$s</xliff:g> ؟"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"إضافة لغة"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"تفضيل المنطقة"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"اكتب اسم اللغة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 00617a5..aa2fbc5 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"অসুবিধা নিদিবৰ কনফিগাৰেশ্বনক পঢ়িবলৈ আৰু সালসলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"চোৱাৰ অনুমতিৰ ব্যৱহাৰ আৰম্ভ কৰক"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ধাৰকক কোনো এপৰ বাবে অনুমতিৰ ব্যৱহাৰ আৰম্ভ কৰিবলৈ দিয়ে। সাধাৰণ এপ্‌সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট লক্ষ্য"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"সাধ্য সুবিধাসমূহৰ শ্বৰ্টকাট লক্ষ্য নির্ধাৰণ কৰিবলৈ এটা এপক অনুমতি দিয়ে।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"পাছৱর্ডৰ নিয়ম ছেট কৰক"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"স্ক্ৰীণ লক পাছৱৰ্ড আৰু পিনৰ দৈর্ঘ্য আৰু কি কি আখৰ ব্যৱহাৰ কৰিব পাৰে তাক নিয়ন্ত্ৰণ কৰক।"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"স্ক্ৰীণ আনলক কৰা প্ৰয়াসবোৰ পৰ্যবেক্ষণ কৰিব পাৰে"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"টেষ্ট হাৰনেছ ম’ড সক্ষম কৰা আছে"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"টেষ্ট হাৰনেছ ম’ড অক্ষম কৰিবলৈ ফেক্টৰী ৰিছেট কৰক।"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"ক্ৰমিক কনছ’ল সক্ষম কৰা আছে"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"কাৰ্যক্ষমতা প্ৰভাৱিত হৈছে। অক্ষম কৰিবলৈ বুটল’ডাৰ পৰীক্ষা কৰক।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"ইউএছবি প’ৰ্টত তৰল বা ধূলি-মাকতি আছে"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"ইউএছবি প’ৰ্ট স্বয়ংক্ৰিয়ভাৱে অক্ষম কৰা হয়। অধিক জানিবৰ বাবে টিপক।"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"ইউএছবি প’ৰ্ট ব্যৱহাৰ কৰাত সমস্যা নাই"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"শ্ৰেণীবদ্ধ নকৰা"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"এই জাননীবোৰৰ গুৰুত্ব আপুনি ছেট কৰব লাগিব।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"এই কার্যৰ সৈতে জড়িত থকা লোকসকলক ভিত্তি কৰি এইয়া গুৰুত্বপূর্ণ বুলি বিবেচনা কৰা হৈছ।"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ (এই একাউণ্টটোৰ এজন ব্যৱহাৰকাৰী ইতিমধ্যে আছে) জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g>ক <xliff:g id="ACCOUNT">%2$s</xliff:g>ৰ জৰিয়তে এজন নতুন ব্যৱহাৰকাৰী সৃষ্টি কৰিবলৈ অনুমতি দিবনে?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ভাষা যোগ কৰক"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ভাষাৰ নাম লিখক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index f79decd..5709bfd 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Tətbiqə \"Narahat Etməyin\" konfiqurasiyasını oxumağa və yazmağa icazə verin."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"Baxış icazəsinin istifadəsinə başlayın"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Sahibinə tətbiqin icazədən istifadəsinə başlamağa imkan verir. Adi tətbiqlər üçün heç vaxt tələb edilmir."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"əlçatımlılıq qısayolunun hədəfi"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Tətbiqə əlçatımlılıq qısayolunun hədəfini müəyyən etməyə imkan verir."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qaydalarını təyin edin"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran kilidinin parolu və PINlərində icazə verilən uzunluq və simvollara nəzarət edin."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Ekranı kiliddən çıxarmaq üçün edilən cəhdlərə nəzarət edin"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USb debaqı deaktivasiya etməyi seçin."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Rejimi aktivdir"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Test Rejimini deaktiv etmək üçün fabrika ayarlarına sıfırlayın."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Ardıcıl konsol aktiv edildi"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performansa təsir edir. Deaktiv etmək üçün yükləyicini yoxlayın."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB portuna maye sızıb və ya qırılıb"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB portu avtomatik deaktiv edildi. Ətraflı məlumat üçün klikləyin."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB portundan istifadə etmək üçün OK"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Kateqoriyasız"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bildirişlərin əhəmiyyətini Siz ayarlaryırsınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"İnsanlar cəlb olunduğu üçün bu vacibdir."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> (artıq bu hesabı olan İstifadəçi mövcuddur) ilə yeni İstifadəçi yaratmağa icazə verilsin?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> tətbiqinə <xliff:g id="ACCOUNT">%2$s</xliff:g> ilə yeni İstifadəçi yartmağa icazə verilsin?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dil əlavə edin"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region seçimi"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını daxil edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 10dc339..0e33329 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -27,7 +27,7 @@
     <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
     <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
-    <string name="untitled" msgid="4638956954852782576">"&lt;Bez naslova&gt;"</string>
+    <string name="untitled" msgid="4638956954852782576">"&lt;Bez imena&gt;"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Nema broja telefona)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Nepoznato"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Glasovna pošta"</string>
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Dozvoljava aplikaciji da čita i upisuje konfiguraciju podešavanja Ne uznemiravaj."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"početak korišćenja dozvole za pregled"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Dozvoljava vlasniku da započne korišćenje dozvole za aplikaciju. Nikada ne bi trebalo da bude potrebna za uobičajene aplikacije."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cilj prečice za pristupačnost"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Dozvoljava aplikaciji da definiše cilj prečice za pristupačnost."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Podešavanje pravila za lozinku"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontroliše dužinu i znakove dozvoljene u lozinkama i PIN-ovima za zaključavanje ekrana."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Nadgledajte pokušaje otključavanja ekrana"</string>
@@ -1383,6 +1385,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Omogućen je režim probnog korišćenja"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Obavite resetovanje na fabrička podešavanja da biste onemogućili režim probnog korišćenja."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serijska konzola je omogućena"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Učinak je smanjen. Da biste onemogući konzolu, proverite pokretački program."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Tečnost ili nečistoća u USB portu"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port je automatski isključen. Dodirnite da biste saznali više."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Korišćenje USB porta je dozvoljeno"</string>
@@ -1924,10 +1928,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nekategorizovano"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi podešavate važnost ovih obaveštenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je važno zbog ljudi koji učestvuju."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik sa tim nalogom već postoji)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Želite li da dozvolite da <xliff:g id="APP">%1$s</xliff:g> napravi novog korisnika sa nalogom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dodajte jezik"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Podešavanje regiona"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index ce65bea..662290d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Дазваляе праграме чытаць і выконваць запіс у канфігурацыю рэжыму «Не турбаваць»."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"запусціць выкарыстанне дазволаў на прагляд"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Дазваляе трымальніку запусціць выкарыстанне дазволаў праграмай. Не патрэбна для звычайных праграм."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"Аб\'екты хуткага доступу да спецыяльных магчымасцей"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Праграма зможа вызначаць аб\'екты хуткага доступу да спецыяльных магчымасцей."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устанавіць правілы паролю"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Кіраваць даўжынёй і сімваламі, дазволенымі пры ўводзе пароляў і PIN-кодаў блакіроўкі экрана."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Сачыць за спробамі разблакіроўкі экрана"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Выберыце, каб адключыць адладку USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Тэставы рэжым уключаны"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Каб выключыць тэставы рэжым, скіньце налады да заводскіх значэнняў."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Паслядоўная кансоль уключана"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Змянілася эфектыўнасць. Каб выключыць, праверце загрузчык."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Вадкасць або смецце ў порце USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Порт USB аўтаматычна адключаны. Каб даведацца больш, націсніце тут."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Порт USB можна выкарыстоўваць"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Некатэгарызаванае"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Вы задалі важнасць гэтых апавяшчэнняў."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Гэта важна, бо з гэтым звязаны пэўныя людзі."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g> (Карыстальнік з гэтым уліковым запісам ужо існуе)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Дазволіць праграме \"<xliff:g id="APP">%1$s</xliff:g>\" стварыць новага Карыстальніка з уліковым запісам <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Дадаць мову"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Параметры рэгіёна"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Увядзіце назву мовы"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 87ea6de..28949d1 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Предоставя на приложението достъп за четене и запис до конфигурацията на „Не безпокойте“."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"стартиране на прегледа на използваните разрешения"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Разрешава на притежателя да стартира прегледа на използваните разрешения за дадено приложение. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"цел на прекия път към функцията за достъпност"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Разрешава на приложението да определя целта на прекия път към функцията за достъпност."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролира дължината и разрешените знаци за паролите и ПИН кодовете за заключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изберете, за да деактивирате отстраняването на грешки през USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Режимът за тестова среда е активиран"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Възстановете фабричните настройки, за да деактивирате режима за тестова среда."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Серийната конзола е активирана"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ефективността е засегната. За да деактивирате, проверете програмата за първоначално зареждане."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Течност или замърсяване в USB порта"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB портът е деактивиран автоматично. Докоснете, за да научите повече."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Можете да използвате USB порта"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Некатегоризирани"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Зададохте важността на тези известия."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Това е важно заради участващите хора."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g> (вече съществува потребител с този профил)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Да се разреши ли на <xliff:g id="APP">%1$s</xliff:g> да създаде нов потребител с профила <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Добавяне на език"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Предпочитание за региона"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Въведете име на език"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index c0843ea..f88e778 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"অ্যাপটিকে \'বিরক্ত করবে না\' কনফিগারেশন পড়া এবং লেখার অনুমতি দেয়।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"দেখার অনুমতি কাজে লাগানো শুরু করুন"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"কোনও অ্যাপের কোনও নির্দিষ্ট অনুমতির ব্যবহার শুরু করার ক্ষেত্রে হোল্ডারকে সাহায্য করে। সাধারণ অ্যাপের জন্য এটির পরিবর্তন হওয়ার কথা নয়।"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"অ্যাক্সেসিবিলিটির শর্টকাটের টার্গেট"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"এটি একটি অ্যাপকে অ্যাক্সেসিবিলিটির শর্টকাটের টার্গেটকে ব্যাখ্যা করতে অনুমতি দেয়।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"পাসওয়ার্ড নিয়মগুলি সেট করে"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"স্ক্রিন লক করার পাসওয়ার্ডগুলিতে অনুমতিপ্রাপ্ত অক্ষর এবং দৈর্ঘ্য নিয়ন্ত্রণ করে৷"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"স্ক্রিন আনলক করার প্রচেষ্টাগুলির উপরে নজর রাখুন"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ডিবাগিং অক্ষম করতে বেছে নিন।"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"টেস্ট হারনেস মোড চালু আছে"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"টেস্ট হারনেস মোড বন্ধ করতে ফ্যাক্টরি রিসেট করুন।"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"সিরিয়াল কনসোল চালু করা হয়েছে"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"পারফর্ম্যান্সে এর প্রভাব পড়বে। চালানো বন্ধ করতে \'বুটলোডার\' প্রোগ্রামে এটিকে চেক করে দেখুন।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"ইউএসবি পোর্টে তরল পদার্থ অথবা ধুলো কণা"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"ইউএসবি পোর্ট নিজে থেকে বন্ধ করা হবে। আরও জানতে ট্যাপ করুন।"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"ইউএসবি পোর্ট ব্যবহার করা যেতে পারে"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"বিভাগ নির্ধারিত নয়"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"আপনি এই বিজ্ঞপ্তিগুলির গুরুত্ব সেট করেছেন।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"লোকজন জড়িত থাকার কারণে এটি গুরুত্বপূর্ণ।"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ (একজন ব্যবহারকারী এই অ্যাকাউন্টে আগে থেকেই রয়েছেন) একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g>-এ একজন নতুন ব্যবহারকারী তৈরি করার অনুমতি <xliff:g id="APP">%1$s</xliff:g>-কে দেবেন?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"একটি ভাষা যোগ করুন"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"পছন্দের অঞ্চল"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ভাষার নাম লিখুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 0d4b12c..ae075cc 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Omogućava aplikaciji da čita i upisuje konfiguraciju načina rada Ne ometaj."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"pokrenuti korištenje odobrenja za pregled"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Dozvoljava vlasniku da pokrene korištenje odobrenja za aplikaciju. Ne bi trebalo biti potrebno za obične aplikacije."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cilj prečice pristupačnosti"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Omogućava aplikaciji da definira cilj prečice pristupačnosti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavljanje pravila za lozinke"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolira dužinu i znakove koji su dozvoljeni u lozinkama za zaključavanje ekrana i PIN-ovima."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Prati pokušaje otključavanja ekrana"</string>
@@ -1385,6 +1387,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Odaberite da onemogućite ispravljanje grešaka koristeći USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Omogućen način rada okvira za testiranje"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Izvršite vraćanje na fabričke postavke da onemogućite način rada okvira za testiranje."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serijska konzola omogućena"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Izvedba je otežana. Da onemogućite, provjerite program za učitavanje operativnog sistema."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Tečnost ili nečistoće u USB priključku"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB priključak je automatski onemogućen. Dodirnite da saznate više."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB priključak je sada sigurno koristiti"</string>
@@ -1926,10 +1930,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nije kategorizirano"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi određujete značaj ovih obavještenja."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Dozvoliti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dodajte jezik"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Upišite ime jezika"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d828844..0427569 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permet que l\'aplicació llegeixi la configuració No molestis i hi escrigui."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"comença a utilitzar el permís de visualització"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permet que un propietari comenci a utilitzar el permís amb una aplicació. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"objectiu de la drecera d\'accessibilitat"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permet a una aplicació definir l\'objectiu de la drecera d\'accessibilitat."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Permet controlar la longitud i el nombre de caràcters permesos a les contrasenyes i als PIN del bloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Supervisar els intents de desbloqueig de la pantalla"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecciona per desactivar la depuració per USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"S\'ha activat el mode Agent de prova"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Si vols desactivar el mode Agent de prova, restableix les dades de fàbrica."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"S\'ha activat la consola de sèrie"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"El rendiment s\'ha vist afectat. Per desactivar-la, comprova el bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Hi ha líquid o pols al port USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"El port USB es desactiva automàticament. Toca per obtenir més informació."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Ja pots utilitzar el port USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sense classificar"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Has definit la importància d\'aquestes notificacions."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Aquest missatge és important per les persones implicades."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ja hi ha un usuari amb aquest compte.)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Concedeixes permís a <xliff:g id="APP">%1$s</xliff:g> per crear un usuari amb el compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Afegeix un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferència de regió"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nom de l\'idioma"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2b524ae..32dac4d 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Umožňuje aplikaci číst a zapisovat konfiguraci režimu Nerušit."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"zahájení zobrazení využití oprávnění"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Umožňuje přístup zahájit využití oprávnění jiné aplikace. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cíl zkratky přístupnosti"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Umožňuje aplikaci definovat cíl zkratky přístupnosti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ovládání délky a znaků povolených v heslech a kódech PIN zámku obrazovky."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Sledovat pokusy o odemknutí obrazovky"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, chcete-li zakázat ladění přes USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Režim správce testů je aktivní"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Chcete-li deaktivovat režim správce testů, restartujte zařízení do továrního nastavení."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Je zapnutá sériová konzole"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Toto má dopad na výkon. Chcete-li ji vypnout, zkontrolujte bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Kapalina nebo nečistota v portu USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Port USB byl automaticky deaktivován. Klepnutím zobrazíte další informace."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Port USB lze bezpečně použít"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Neklasifikováno"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Důležitost oznámení určujete vy."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tato zpráva je důležitá kvůli lidem zapojeným do konverzace."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Uživatel s tímto účtem již existuje.)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Povolit aplikaci <xliff:g id="APP">%1$s</xliff:g> vytvořit nového uživatele s účtem <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Přidat jazyk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferovaná oblast"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Zadejte název jazyka"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4d57a90..3d79588 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -226,7 +226,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Indstillinger for telefon"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
-    <string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødsituation"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
     <string name="global_action_logout" msgid="935179188218826050">"Afslut sessionen"</string>
     <string name="global_action_screenshot" msgid="8329831278085426283">"Screenshot"</string>
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og redigere konfigurationen af Forstyr ikke."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start brugen at tilladelsesvisning"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Tillader, at brugeren kan bruge en tilladelse for en app. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"mål for hjælpefunktionsgenvej"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Tillader, at en app definerer målet for en hjælpefunktionsgenvej."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angiv regler for adgangskoder"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Tjek længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vælg for at deaktivere USB-fejlretning."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Tilstanden Testsele er aktiveret"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Gendan fabriksindstillingerne for at deaktivere tilstanden Testsele."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seriekonsollen er aktiveret"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Effektiviteten er påvirket. Deaktiver via bootloaderen."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Væske eller snavs i USB-porten"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-porten deaktiveres automatisk. Tryk for at få flere oplysninger."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-porten kan bruges"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uden kategori"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du angiver, hvor vigtige disse notifikationer er."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er vigtigt på grund af de personer, det handler om."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en ny bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g> (der findes allerede en bruger med denne konto)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Vil du give <xliff:g id="APP">%1$s</xliff:g> tilladelse til at oprette en nye bruger med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Tilføj et sprog"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Områdeindstilling"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Angiv sprog"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2ec70d3..cbba324 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ermöglicht der App Lese- und Schreibzugriff auf die \"Bitte nicht stören\"-Konfiguration"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"Mit der Verwendung der Anzeigeberechtigung beginnen"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Ermöglicht dem Inhaber, die Berechtigungsnutzung für eine App zu beginnen. Sollte für normale Apps nie benötigt werden."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"Ziel der Verknüpfung für Bedienungshilfen"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Ermöglicht einer App, das Ziel der Verknüpfung für Bedienungshilfen zu definieren."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Zulässige Länge und Zeichen für Passwörter für die Displaysperre festlegen"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -1361,7 +1363,9 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test-Harnischmodus aktiviert"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Setz das Gerät auf die Werkseinstellungen zurück, um den Test-Harnischmodus zu deaktivieren."</string>
-    <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Flüssigkeiten oder Fremdkörper im USB-Port"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serielle Konsole aktiviert"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Leistung wird beeinflusst. Überprüfe Bootloader zum Deaktivieren."</string>
+    <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Flüssigkeit oder Fremdkörper im USB-Port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Der USB-Port wird automatisch deaktiviert. Für weitere Informationen tippen."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-Port kann wieder verwendet werden"</string>
     <string name="usb_contaminant_not_detected_message" msgid="2415791798244545292">"Das Smartphone erkennt keine Flüssigkeiten oder Fremdkörper mehr."</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Unkategorisiert"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du hast die Wichtigkeit dieser Benachrichtigungen festgelegt."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Diese Benachrichtigung ist aufgrund der beteiligten Personen wichtig."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Es gibt bereits einen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g>. Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit diesem Konto erstellt?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Möchtest du zulassen, dass <xliff:g id="APP">%1$s</xliff:g> einen neuen Nutzer mit <xliff:g id="ACCOUNT">%2$s</xliff:g> erstellt?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Sprache hinzufügen"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region auswählen"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sprache eingeben"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 6998c0c..e162d6b 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Επιτρέπει στην εφαρμογή την εγγραφή και τη σύνταξη διαμόρφωσης για τη λειτουργία \"Μην ενοχλείτε\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"έναρξη χρήσης άδειας προβολής"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Επιτρέπει στον κάτοχο να ξεκινήσει τη χρήση της άδειας για μια εφαρμογή. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"στόχος συντόμευσης προσβασιμότητας"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Επιτρέπει σε μια εφαρμογή να καθορίσει τον στόχο της συντόμευσης προσβασιμότητας."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Η λειτουργία περιβάλλοντος δοκιμών ενεργοποιήθηκε"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Εκτελέστε επαναφορά εργοστασιακών ρυθμίσεων για να απενεργοποιήσετε τη λειτουργία περιβάλλοντος δοκιμών."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Η σειριακή κονσόλα ενεργοποιήθηκε"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Η απόδοση επηρεάζεται. Για απενεργοποίηση, επιλέξτε το πρόγραμμα φόρτωσης εκκίνησης."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Υγρασία ή ακαθαρσίες στη θύρα USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Η θύρα USB απενεργοποιείται αυτόματα. Πατήστε για να μάθετε περισσότερα."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Αποδεκτή η χρήση της θύρας USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Μη κατηγοριοποιημένο"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Μπορείτε να ρυθμίσετε τη βαρύτητα αυτών των ειδοποιήσεων."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Αυτό είναι σημαντικό λόγω των ατόμων που συμμετέχουν."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g> (υπάρχει ήδη χρήστης με αυτόν τον λογαριασμό);"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Επιτρέπετε στην εφαρμογή <xliff:g id="APP">%1$s</xliff:g> να δημιουργήσει έναν νέο χρήστη με τον λογαριασμό <xliff:g id="ACCOUNT">%2$s</xliff:g>;"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Προσθήκη γλώσσας"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Προτίμηση περιοχής"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Εισαγ. όνομα γλώσσας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 7c2b329..56d09f3 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Allows the app to read and write Do Not Disturb configuration."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start view permission usage"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Allows the holder to start the permission usage for an app. Should never be needed for normal apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"accessibility shortcut target"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Allows an app to define the accessibility shortcut target."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitor screen unlock attempts"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Harness Mode enabled"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Perform a factory reset to disable Test Harness Mode."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serial console enabled"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performance is impacted. To disable, check bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquid or debris in USB port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port is automatically disabled. Tap to learn more."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK to use USB port"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uncategorised"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 6da3a5f..2aafb7a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Allows the app to read and write Do Not Disturb configuration."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start view permission usage"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Allows the holder to start the permission usage for an app. Should never be needed for normal apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"accessibility shortcut target"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Allows an app to define the accessibility shortcut target."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitor screen unlock attempts"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Harness Mode enabled"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Perform a factory reset to disable Test Harness Mode."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serial console enabled"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performance is impacted. To disable, check bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquid or debris in USB port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port is automatically disabled. Tap to learn more."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK to use USB port"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uncategorised"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7c2b329..56d09f3 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Allows the app to read and write Do Not Disturb configuration."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start view permission usage"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Allows the holder to start the permission usage for an app. Should never be needed for normal apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"accessibility shortcut target"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Allows an app to define the accessibility shortcut target."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitor screen unlock attempts"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Harness Mode enabled"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Perform a factory reset to disable Test Harness Mode."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serial console enabled"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performance is impacted. To disable, check bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquid or debris in USB port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port is automatically disabled. Tap to learn more."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK to use USB port"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uncategorised"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 7c2b329..56d09f3 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Allows the app to read and write Do Not Disturb configuration."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start view permission usage"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Allows the holder to start the permission usage for an app. Should never be needed for normal apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"accessibility shortcut target"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Allows an app to define the accessibility shortcut target."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitor screen unlock attempts"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Harness Mode enabled"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Perform a factory reset to disable Test Harness Mode."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serial console enabled"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performance is impacted. To disable, check bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquid or debris in USB port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port is automatically disabled. Tap to learn more."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK to use USB port"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uncategorised"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"You set the importance of these notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"This is important because of the people involved."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g> (a User with this account already exists)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Add a language"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Region preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Type language name"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 62f294e..9844b67 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‎‎Allows the app to read and write Do Not Disturb configuration.‎‏‎‎‏‎"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎start view permission usage‎‏‎‎‏‎"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎‎Allows the holder to start the permission usage for an app. Should never be needed for normal apps.‎‏‎‎‏‎"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‏‏‎‎‏‎accessibility shortcut target‎‏‎‎‏‎"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎Allows an app to define the accessibility shortcut target.‎‏‎‎‏‎"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎Set password rules‎‏‎‎‏‎"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‎‏‏‎‎‎‎Control the length and the characters allowed in screen lock passwords and PINs.‎‏‎‎‏‎"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎Monitor screen unlock attempts‎‏‎‎‏‎"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‎Select to disable USB debugging.‎‏‎‎‏‎"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‎‏‎‎‏‏‎Test Harness Mode enabled‎‏‎‎‏‎"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎Perform a factory reset to disable Test Harness Mode.‎‏‎‎‏‎"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎Serial console enabled‎‏‎‎‏‎"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎Performance is impacted. To disable, check bootloader.‎‏‎‎‏‎"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‏‏‏‎‏‏‎‏‎Liquid or debris in USB port‎‏‎‎‏‎"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎USB port is automatically disabled. Tap to learn more.‎‏‎‎‏‎"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎OK to use USB port‎‏‎‎‏‎"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎Uncategorized‎‏‎‎‏‎"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‎You set the importance of these notifications.‎‏‎‎‏‎"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎This is important because of the people involved.‎‏‎‎‏‎"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ (a User with this account already exists) ?‎‏‎‎‏‎"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to create a new User with ‎‏‎‎‏‏‎<xliff:g id="ACCOUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎ ?‎‏‎‎‏‎"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‎Add a language‎‏‎‎‏‎"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‎‏‎Region preference‎‏‎‎‏‎"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‎Type language name‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7346bd0..7289f4b 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite que la aplicación lea y modifique la configuración de la función No interrumpir."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar uso de permiso de vista"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite que el propietario inicie el uso de permisos para una app. No debería requerirse para apps normales."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"orientación del acceso directo de accesibilidad"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite que una app defina la orientación del acceso directo de accesibilidad."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para desactivar la depuración por USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Se habilitó el modo de agente de prueba"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Restablece la configuración de fábrica para inhabilitar el modo de agente de prueba."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Se habilitó la consola en serie"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Afecta el rendimiento. Para inhabilitarla, verifica bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Hay líquido o suciedad en el puerto USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"El puerto USB se inhabilitó automáticamente. Presiona para obtener más información."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Se puede usar el puerto USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sin categoría"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Estableciste la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Es importante debido a las personas involucradas."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"¿Quieres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Ya existe un usuario con esta cuenta)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"¿Deseas permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario nuevo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Agregar un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre del idioma"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6c1c992..c513b39 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite que la aplicación lea y modifique la configuración de No molestar."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar uso de permiso de visualización"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite que el titular inicie el uso de permisos de una aplicación. Las aplicaciones normales no deberían necesitar nunca este permiso."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"objetivo de atajo de accesibilidad"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite que una aplicación defina el objetivo de un atajo de accesibilidad."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla la longitud y los caracteres permitidos en los PIN y en las contraseñas de bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Supervisar los intentos de desbloqueo de pantalla"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modo de agente de prueba habilitado"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Restablece los ajustes de fábrica para inhabilitar el modo de agente de prueba."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Se ha habilitado la consola en serie"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Afecta al rendimiento. Para inhabilitarlo, comprueba el bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Se ha detectado líquido o suciedad en el puerto USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"El puerto USB se ha inhabilitado automáticamente. Toca para obtener más información."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Se puede utilizar el puerto USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sin clasificar"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Tú determinas la importancia de estas notificaciones."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Esto es importante por los usuarios implicados."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>, que ya tiene uno?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"¿Permitir que <xliff:g id="APP">%1$s</xliff:g> cree otro usuario con la cuenta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Añadir un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nombre de idioma"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 28d1203..d70a580 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Võimaldab rakendusel lugeda ja kirjutada funktsiooni Mitte segada seadistusi."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"vaatamisloa kasutamise alustamine"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Võimaldab omanikul rakenduse puhul alustada loa kasutamist. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"juurdepääsetavuse otsetee sihtmärk"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Lubab rakendusel määrata juurdepääsetavuse otsetee sihtmärgi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Juhitakse ekraaniluku paroolide ja PIN-koodide pikkusi ning lubatud tähemärkide seadeid."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Ekraani avamiskatsete jälgimine"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Valige USB silumise keelamiseks"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Testrakendirežiim on lubatud"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Testrakendirežiimi keelamiseks taastage tehaseseaded."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seeriakonsool on lubatud"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"See mõjutab toimivust. Keelamiseks kontrollige käivituslaadurit."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB-pordis on vedelik või mustus"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-port on automaatselt keelatud. Puudutage lisateabe saamiseks."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-porti tohib kasutada"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Kategoriseerimata"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Teie määrasite nende märguannete tähtsuse."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"See on tähtis osalevate inimeste tõttu."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g> (selle kontoga kasutaja on juba olemas)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Kas lubada rakendusel <xliff:g id="APP">%1$s</xliff:g> luua uus kasutaja kontoga <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Keele lisamine"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Piirkonnaeelistus"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sisestage keele nimi"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 9460ee7..3a9cb13 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"Ez molestatu\" konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"hasi ikusteko baimena erabiltzen"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Aplikazioaren baimena erabiltzen hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"erabilerraztasun-lasterbidearen helburua"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Erabilerraztasun-lasterbidearen helburua zehazteko baimena ematen dio aplikazioari."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolatu pantaila blokeoaren pasahitzen eta PINen luzera eta onartutako karaktereak."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Gainbegiratu pantaila desblokeatzeko saiakerak"</string>
@@ -1260,7 +1262,7 @@
     <string name="wifi_suggestion_title" msgid="6396033039578436801">"Iradokitako wifi-sareak baimendu nahi dituzu?"</string>
     <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> aplikazioak sare batzuk iradoki ditu. Baliteke gailua automatikoki konektatzea."</string>
     <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Baimendu"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ez. Eskerrik asko."</string>
+    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ez, eskerrik asko"</string>
     <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi konexioa automatikoki aktibatuko da"</string>
     <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Gordeta daukazun kalitate handiko sare batetik gertu zaudenean"</string>
     <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ez aktibatu berriro"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Hautatu USB arazketa desgaitzeko."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Proba-materialeko modua gaitu da"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Proba-materialaren modua desgaitzeko, berrezarri jatorrizko datuak."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serie-kontsola gaituta dago"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Funtzionamenduari eragiten dio. Desgaitzeko, joan abiarazlera."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Likidoa edo zikinkeriak daude USB atakan"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ataka automatikoki desgaitu da. Informazio gehiago lortzeko, sakatu hau."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Erabiltzeko moduan dago USB ataka"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Kategoriarik gabea"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Zuk ezarri duzu jakinarazpen hauen garrantzia."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu? (Badago kontu hori duen erabiltzaile bat)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzeko baimena eman nahi diozu?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Lurralde-hobespena"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ec5dbcb2..f0ea22d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"به برنامه امکان می‌دهد پیکربندی «مزاحم نشوید» را بخواند و بنویسد."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"شروع مشاهده استفاده از مجوز"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"به دارنده اجازه شروع استفاده از مجوز را برای برنامه می‌دهد. هرگز برای برنامه‌های معمول نیاز نیست."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"مقصد میان‌بر دسترس‌پذیری"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"به برنامه اجازه می‌دهد مقصد میانبر دسترس‌پذیری را تعریف کند."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین گذرواژه"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"کنترل طول و نوع نویسه‌هایی که در گذرواژه و پین قفل صفحه مجاز است."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"پایش تلاش‌های باز کردن قفل صفحه"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏انتخاب کنید تا رفع عیب USB غیرفعال شود."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"«حالت مجموعه داده‌های تست» فعال شد"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"برای غیرفعال کردن «حالت مجموعه داده‌های تست»، بازنشانی کارخانه‌ای کنید."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"کنسول سریال فعال است"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"‏عملکرد تحت‌تأثیر قرار گرفته است. برای غیرفعال کردن، bootloader را بررسی کنید."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"‏مایعات یا خاکروبه در درگاه USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"‏درگاه USB به‌طور خودکار غیرفعال شده است. برای اطلاعات بیشتر، ضربه بزنید."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"‏می‌توان از درگاه USB استفاده کرد"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"دسته‌بندی‌نشده"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"شما اهمیت این اعلان‌ها را تنظیم می‌کنید."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"به دلیل افراد درگیر مهم است."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"به<xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> (کاربری با این حساب درحال‌حاضر وجود دارد) کاربری جدید ایجاد کند؟"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"به <xliff:g id="APP">%1$s</xliff:g> اجازه می‌دهید با <xliff:g id="ACCOUNT">%2$s</xliff:g> کاربری جدید ایجاد کند؟"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"افزودن زبان"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"اولویت‌های منطقه"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"نام زبان را تایپ کنید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a94253b..b1648f5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Sallii sovelluksen lukea ja muokata Älä häiritse -tilan asetuksia."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"aloita katseluoikeuksien käyttö"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Antaa luvanhaltijan käynnistää sovelluksen käyttöoikeuksien käytön. Ei tavallisten sovelluksien käyttöön."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"esteettömyystilan pikakuvakkeen kohde"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Sallii sovelluksen määrittää kohteen esteettömystilan pikakuvakkeelle."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Asentaa salasanasäännöt"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Hallinnoida ruudun lukituksen salasanoissa ja PIN-koodeissa sallittuja merkkejä ja niiden pituutta."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Tarkkailla näytön avaamisyrityksiä"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Testikehystila käytössä"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Palauta tehdasasetukset, niin voit poistaa testikehystilan käytöstä."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Sarjakonsoli käytössä"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Tämä vaikuttaa suorituskykyyn. Jos haluat poistaa toiminnon käytöstä, tarkista käynnistysohjelma."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Nestettä tai likaa USB-portissa"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-portti poistetaan käytöstä automaattisesti. Napauta nähdäksesi lisätietoja."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-portin käyttö on sallittu"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Luokittelematon"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Voit valita näiden ilmoitusten tärkeyden."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tämä on tärkeää siihen liittyvien ihmisten perusteella."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>) – tällä käyttäjällä on jo tili?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Saako <xliff:g id="APP">%1$s</xliff:g> luoda uuden käyttäjän (<xliff:g id="ACCOUNT">%2$s</xliff:g>)?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Lisää kieli"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Alueasetus"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Anna kielen nimi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 94f6acb..384f5fa 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permet à l\'application de consulter et de modifier la configuration du mode Ne pas déranger."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"démarrer l\'affichage de l\'usage des autorisations"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permet au détenteur de démarrer l\'usage des autorisations pour une application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cible du raccourci d\'accessibilité"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permet à une application de définir la cible du raccourci d\'accessibilité."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les NIP de verrouillage de l\'écran."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Mode Logiciel de test activé"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Effectuez une réinitialisation pour désactiver le mode Logiciel de test."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"La console série est activée"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"La performance est réduite. Pour désactiver cette fonction, vérifier le programme d\'amorçage."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquide ou débris dans le port USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Le port USB est désactivé automatiquement. Touchez ici pour en savoir plus."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Autorisation d\'utiliser le port USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sans catégorie"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un utilisateur <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Un utilisateur est déjà associé à ce compte)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil d\'utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Entrez la langue"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 11ba7dc..d204ac1 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permet à l\'application de consulter et de modifier la configuration du mode Ne pas déranger."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"activer l\'utilisation de l\'autorisation d\'affichage"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permet à l\'application autorisée d\'activer l\'utilisation de l\'autorisation pour une application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cible du raccourci d\'accessibilité"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Autorise une application à définir la cible du raccourci d\'accessibilité."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les codes d\'accès de verrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Mode Atelier de test activé"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Rétablissez la configuration d\'usine pour désactiver le mode Atelier de test."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Console série activée"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Les performances sont affectées. Pour désactiver la console série, vérifiez le bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Présence de liquide ou de saletés dans le port USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Le port USB est désactivé automatiquement. Appuyez sur cette notification pour en savoir plus."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Le port USB peut être utilisé"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sans catégorie"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vous définissez l\'importance de ces notifications."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ces notifications sont importantes en raison des participants."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> (un utilisateur associé à ce compte existe déjà) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Autoriser <xliff:g id="APP">%1$s</xliff:g> à créer un profil utilisateur avec le compte <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Ajouter une langue"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Saisissez la langue"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 1becada..b798bc5 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite á aplicación ler e escribir a configuración do modo Non molestar."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar uso de permiso de vista"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite ao propietario iniciar o uso de permisos dunha aplicación. As aplicacións normais non deberían precisalo nunca."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"obxectivo do atallo de accesibilidade"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite que unha aplicación defina o obxectivo do atallo de accesibilidade."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer as normas de contrasinal"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla a lonxitude e os caracteres permitidos nos contrasinais e nos PIN de bloqueo da pantalla."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Controlar os intentos de desbloqueo da pantalla"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecciona a opción para desactivar a depuración por USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Activouse o modo de axente de proba"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Restablece a configuración de fábrica para desactivar o modo de axente de proba."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"A consola de serie está activada"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"O rendemento vese afectado. Para desactivar a consola, comproba o cargador de arranque."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Hai líquido ou residuos no porto USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"O porto USB desactivouse automaticamente. Toca para obter máis información."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Pódese utilizar o porto USB"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sen clasificar"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ti defines a importancia destas notificacións."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante polas persoas involucradas."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Xa existe un usuario con esta conta)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Queres permitir que <xliff:g id="APP">%1$s</xliff:g> cree un usuario novo con <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Engadir un idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferencia de rexión"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nome do idioma"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 09661c1..5a41503 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"એપ્લિકેશનને ખલેલ પાડશો નહીં ગોઠવણી વાંચવા અને લખવાની મંજૂરી આપે છે."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"પરવાનગી વપરાશ જુઓને શરૂ કરો"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"કોઈ ઍપ માટે પરવાનગી વપરાશ શરૂ કરવાની ધારકને મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂર પડી ન શકે."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ઍક્સેસિબિલિટી શૉર્ટકટ ટાર્ગેટ"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ઍપને ઍક્સેસિબિલિટી શૉર્ટકટ ટાર્ગેટ વ્યાખ્યાતિત કરવાની મંજૂરી આપે છે."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"પાસવર્ડ નિયમો સેટ કરો"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"સ્ક્રીન લૉક પાસવર્ડ અને પિનમાં મંજૂર લંબાઈ અને અક્ષરોને નિયંત્રિત કરો."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"સ્ક્રીનને અનલૉક કરવાના પ્રયત્નોનું નિયમન કરો"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ડિબગીંગને અક્ષમ કરવા માટે પસંદ કરો."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ટેસ્ટ હાર્નેસ મોડ ચાલુ કર્યો"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ટેસ્ટ હાર્નેસ મોડ બંધ કરવા માટે ફૅક્ટરી રીસેટ કરો."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"સિરીયલ કન્સોલ ચાલુ થયો"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"કાર્યપ્રદર્શનને અસર થાય છે. બંધ કરવા માટે, બૂટલોડર ચેક કરો."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB પોર્ટમાં પ્રવાહી કે ધૂળ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB પોર્ટ ઑટોમૅટિક રીતે બંધ કરવામાં આવ્યો છે. વધુ જાણવા માટે ટૅપ કરો."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB પોર્ટનો ઉપયોગ કરવો યોગ્ય છે"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"અવર્ગીકૃત"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"તમે આ સૂચનાઓનું મહત્વ સેટ કર્યું છે."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"શામેલ થયેલ લોકોને કારણે આ મહત્વપૂર્ણ છે."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ (આ એકાઉન્ટ માટે એક વપરાશકર્તા પહેલાંથી અસ્તિત્વમાં છે) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g>ને <xliff:g id="ACCOUNT">%2$s</xliff:g> માટે એક નવા વપરાશકર્તા બનાવવાની મંજૂરી આપીએ ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ભાષા ઉમેરો"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"પ્રદેશ પસંદગી"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ભાષાનું નામ ટાઇપ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f21d138..5b90234 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"ऐप को परेशान न करें कॉन्फ़िगरेशन पढ़ने और लिखने देती है."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"देखने की अनुमतियां चालू करें"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"इस्तेमाल करने वाले को किसी ऐप्लिकेशन के लिए अनुमतियों का इस्तेमाल शुरू करने देता है. सामान्य ऐप्लिकेशन के लिए इसकी ज़रूरत कभी नहीं पड़ती."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"सुलभता शॉर्टकट टारगेट"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"सुलभता शॉर्टकट टारगेट के बारे में बताने के लिए ऐप्लिकेशन को मंज़ूरी दें."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करना"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्‍क्रीन लॉक पासवर्ड और पिन की लंबाई और उनमें स्वीकृत वर्णों को नियंत्रित करना."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"स्‍क्रीन अनलॉक करने के की कोशिशों पर नज़र रखना"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबग करना अक्षम करने के लिए चुनें."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"टेस्ट हार्नेस मोड चालू किया गया"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"टेस्ट हार्नेस मोड बंद करने के लिए फ़ैक्ट्री रीसेट करें."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"सीरियल कंसोल को चालू करें"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"परफ़ॉर्मेंस पर असर पड़ा है. बंद करने के लिए बूटलोडर चुनें."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"यूएसबी पोर्ट में तरल चीज़ या कचरा है"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"यूएसबी पोर्ट अपने आप बंद हो गया है. ज़्यादा जानने के लिए टैप करें."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"यूएसबी पोर्ट का इस्तेमाल करना सुरक्षित है"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"बिना किसी श्रेणी के"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"आपने इन सूचनाओं की अहमियत सेट की है."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के नाम से एक नया उपयोगकर्ता बनाने की अनुमति दें (इस नाम से एक खाता पहले से मौजूद है)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Allow <xliff:g id="APP">%1$s</xliff:g> to create a new User with <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"भाषा जोड़ें"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"क्षेत्र प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा का नाम लिखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 25007d5..291b116 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Omogućuje aplikaciji čitanje i pisanje konfiguracije opcije Ne ometaj."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"pokrenuti upotrebu dopuštenja za pregled"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Dopušta nositelju pokretanje upotrebe dopuštenja za aplikaciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cilj prečaca pristupačnosti"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Aplikaciji omogućuje da definira cilj prečaca pristupačnosti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Upravlja duljinom i znakovima koji su dopušteni u zaporkama i PIN-ovima zaključavanja zaslona."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Nadziri pokušaje otključavanja zaslona"</string>
@@ -1383,6 +1385,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Omogućen je način testnog okvira"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Vratite na tvorničke postavke da biste onemogućili način testnog okvira."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serijska konzola omogućena"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Izvedba je otežana. Provjerite početni program za pokretanje da biste onemogućili konzolu."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Tekućina ili prljavština u USB priključku"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB priključak automatski je onemogućen. Dodirnite da biste saznali više."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Možete koristiti USB priključak"</string>
@@ -1924,10 +1928,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nema kategorije"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Postavili ste važnost tih obavijesti."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Važno je zbog uključenih osoba."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g> (korisnik s ovim računom već postoji)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Dopustiti aplikaciji <xliff:g id="APP">%1$s</xliff:g> da izradi novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dodavanje jezika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Postavke regije"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Unesite naziv jezika"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 0487601a..f83ac69 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Az alkalmazás olvashatja és szerkesztheti a „Ne zavarjanak” funkció beállításait."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"engedélyhasználat megtekintésének elindítása"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Lehetővé teszi a felhasználó számára, hogy elindítsa az alkalmazás engedélyhasználatát. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"A kisegítő lehetőségek gyorsparancs célja"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Engedélyezi az alkalmazásoknak a kisegítő lehetőségek gyorsparancs céljának meghatározását."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"A képernyőzár jelszavaiban és PIN kódjaiban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Válassza ezt az USB hibakeresés kikapcsolásához."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Tesztelési alapkörnyezet mód engedélyezve"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"A Tesztelési alapkörnyezet mód kikapcsolásához állítsa vissza a gyári beállításokat."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Soros konzol engedélyezve"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ez hatással van a teljesítményre. A letiltáshoz ellenőrizze a rendszerindítót."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Folyadék vagy szennyeződés az USB-portban"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-port automatikusan letiltva. Koppintson, ha további információra van szüksége."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Az USB-port rendben használható"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nincs kategóriába sorolva"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ön állította be ezen értesítések fontossági szintjét."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ez az üzenet a résztvevők miatt fontos."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal? (Már létezik felhasználó ezzel a fiókkal.)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Engedélyezi a(z) <xliff:g id="APP">%1$s</xliff:g> számára, hogy új felhasználót hozzon létre a(z) <xliff:g id="ACCOUNT">%2$s</xliff:g> fiókkal?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Nyelv hozzáadása"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Régió beállítása"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Adja meg a nyelvet"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index e6223f0..2c40a5a 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Թույլ է տալիս հավելվածին փոփոխել «Չանհանգստացնել» գործառույթի կազմաձևումը:"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"թույլտվությունների մասին տվյալների հասանելիություն"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Հավելվածին հասանելի կդառնան թույլտվությունների մասին տվյալները։ Այս թույլտվությունն անհրաժեշտ չէ սովորական հավելվածներին։"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"հատուկ գործառույթների դյուրանցումն օգտագործելու նպատակը"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Հավելվածին թույլ է տալիս որոշել հատուկ գործառույթների դյուրանցումն օգտագործելու նպատակը։"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Սեղմեք՝ USB-ով վրիպազերծումն անջատելու համար:"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Թեստային ռեժիմը միացված է"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Թեստային ռեժիմն անջատելու համար զրոյացրեք կարգավորումները։"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Սերիական վահանակը միացված է"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Աշխատանքի արդյունավետությունը նվազում է։ Վահանակն անջատելու համար ստուգեք օպերացիոն համակարգի բեռնիչը։"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB միացքում ջուր կամ աղտ է հայտնաբերվել"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB միացքն ավտոմատ անջատվել է: Հպեք՝ ավելին իմանալու համար:"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB միացքը կարող է օգտագործվել"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Չդասակարգված"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Դուք սահմանել եք այս ծանուցումների կարևորությունը:"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Կարևոր է, քանի որ որոշակի մարդիկ են ներգրավված:"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել (նման հաշվով Օգտատեր արդեն գոյություն ունի):"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Թույլատրե՞լ <xliff:g id="APP">%1$s</xliff:g> հավելվածին <xliff:g id="ACCOUNT">%2$s</xliff:g> հաշվով նոր Օգտատեր ստեղծել:"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Ավելացնել լեզու"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Նախընտրելի տարածաշրջան"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Մուտքագրեք լեզուն"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3c6ee83..4d0eea0 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Mengizinkan aplikasi membaca dan menulis konfigurasi status Jangan Ganggu."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"mulai melihat penggunaan izin"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Memungkinkan pemegang memulai penggunaan izin untuk aplikasi. Tidak diperlukan untuk aplikasi normal."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"target pintasan aksesibilitas"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Mengizinkan aplikasi menentukan target pintasan aksesibilitas."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengontrol panjang dan karakter yang diizinkan dalam sandi dan PIN kunci layar."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Pantau upaya pembukaan kunci layar"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk menonaktifkan debugging USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Mode Tes Otomatis diaktifkan"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Lakukan reset ke setelan pabrik untuk menonaktifkan Mode Tes Otomatis."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Konsol serial diaktifkan"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performa terpengaruh. Untuk menonaktifkan, periksa bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Cairan atau kotoran di port USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Port USB otomatis dinonaktifkan. Ketuk untuk mempelajari lebih lanjut."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Boleh menggunakan port USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Belum dikategorikan"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Anda menyetel nilai penting notifikasi ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ini penting karena orang-orang yang terlibat."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akun ini sudah ada) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Izinkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baru dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferensi wilayah"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ketik nama bahasa"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 59cd4c1..558f4af 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Leyfir forriti að lesa og skrifa í grunnstillingu „Ónáðið ekki“."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"heimildanotkun upphafsyfirlits"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Leyfir handhafa að byrja heimildanotkun fyrir forrit. Ætti aldrei að þurfa fyrir venjuleg forrit."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"áfangastaður aðgengisflýtileiðar"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Leyfir forriti að skilgreina áfangastað aðgengisflýtileiðar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setja reglur um aðgangsorð"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stjórna lengd og fjölda stafa í aðgangsorðum og PIN-númerum skjáláss."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Fylgjast með tilraunum til að taka skjáinn úr lás"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Veldu til að gera USB-villuleit óvirka."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Kveikt á stillingu prófunarvangs"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Núllstilltu til að slökkva á stillingu prófunarvangs."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Raðstjórnborð virkjað"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Þetta hefur áhrif á afköst. Athugaðu ræsiforritið ef þú vilt gera þetta óvirkt."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Vökvi eða óhreinindi í USB-tengi"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-tengi er gert óvirkt sjálfkrafa. Ýttu til að fá frekari upplýsingar."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Óhætt að nota USB-tengi"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Óflokkað"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Þú stilltir mikilvægi þessara tilkynninga."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Þetta er mikilvægt vegna fólksins sem tekur þátt í þessu."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Viltu leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> (notandi með þennan reikning er þegar fyrir hendi)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Leyfa <xliff:g id="APP">%1$s</xliff:g> að stofna nýjan notanda með <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Bæta við tungumáli"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Svæðisval"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Sláðu inn heiti tungumáls"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index cbc9989..d0cded8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Consente all\'app di leggere e modificare la configurazione della funzione Non disturbare."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"avvio dell\'uso dell\'autorizzazione di visualizzazione"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Consente al titolare di avviare l\'uso delle autorizzazioni per un\'app. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"target della scorciatoia Accessibilità"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Consente a un\'app di definire il target della scorciatoia Accessibilità"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Impostare regole per le password"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlla la lunghezza e i caratteri ammessi nelle password e nei PIN del blocco schermo."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitorare tentativi di sblocco dello schermo"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleziona per disattivare il debug USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modalità test harness attivata"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Ripristina le impostazioni di fabbrica per disattivare la modalità test harness."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Console seriale attivata"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ci sono conseguenze sulle prestazioni. Per disattivare, seleziona il bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquidi o detriti nella porta USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"La porta USB viene disattivata automaticamente. Tocca per avere ulteriori informazioni."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Utilizzo porta USB consentito"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Senza categoria"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Stabilisci tu l\'importanza di queste notifiche."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Importante a causa delle persone coinvolte."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g> (esiste già un utente con questo account)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Consentire a <xliff:g id="APP">%1$s</xliff:g> di creare un nuovo utente con l\'account <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Aggiungi una lingua"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Area geografica preferita"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digita nome lingua"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0a721a8..8b2b625 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"מאפשר לאפליקציה לקרוא ולכתוב את התצורה של \'נא לא להפריע\'."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"התחלת צפייה בהרשאות השימוש"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"מאפשרת לבעלים להפעיל את השימוש בהרשאות עבור אפליקציה מסוימת. הרשאה זו אף פעם לא נדרשת עבור אפליקציות רגילות."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"קיצור דרך ליעד של פעולת נגישות"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"מאפשרת לאפליקציה להגדיר את קיצור הדרך ליעד של פעולת נגישות."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"קביעת האורך הנדרש והתווים המותרים בסיסמאות ובקודי הגישה של מסך הנעילה."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"מעקב אחר ניסיונות לביטול של נעילת המסך"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏בחר להשבית ניפוי באגים ב-USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"מצב מסגרת בדיקה הופעל"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"כדי להשבית את מצב מסגרת בדיקה צריך לאפס להגדרות היצרן."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"קונסולה סדרתית מופעלת"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"קיימת השפעה על הביצועים. כדי להשבית, יש לבדוק את תוכנת האתחול."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"‏יש נוזלים או חלקיקים ביציאת ה-USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"‏יציאת ה-USB הושבתה באופן אוטומטי. יש להקיש לקבלת מידע נוסף."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"‏ניתן להשתמש ביציאת ה-USB"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ללא שיוך לקטגוריה"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"עליך להגדיר את החשיבות של ההתראות האלה."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ההודעה חשובה בשל האנשים המעורבים."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> (כבר קיים משתמש לחשבון הזה) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"האם לאפשר לאפליקציה <xliff:g id="APP">%1$s</xliff:g> ליצור משתמש חדש באמצעות <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"הוספת שפה"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"העדפת אזור"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"הקלד שם שפה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index fe45c1f..39f05db 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"サイレント モード設定の読み取りと書き込みをアプリに許可します。"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"表示権限の使用の開始"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"アプリの権限使用の開始を所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ユーザー補助ショートカットのターゲット"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ユーザー補助ショートカットのターゲットの定義付けをアプリに許可します。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"画面ロック解除試行の監視"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USBデバッグを無効にする場合に選択します。"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"テストハーネス モード有効"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"出荷時設定にリセットしてテストハーネス モードを無効にしてください。"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"シリアル コンソールは有効です"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"シリアル コンソールを有効にすると、パフォーマンスに影響します。無効にするには、ブートローダーをチェックしてください。"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ポート内の液体やゴミ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ポートが自動的に無効になりました。タップして詳細をご確認ください。"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB ポートを安全に使用できます"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"カテゴリなし"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"このような通知の重要度を設定します。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"関係するユーザーのため、この設定は重要です。"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?(このアカウントのユーザーはすでに存在します)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> が <xliff:g id="ACCOUNT">%2$s</xliff:g> で新しいユーザーを作成できるようにしますか?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"言語を追加"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地域設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"言語名を入力"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 00afe026..2f216f9 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"საშუალებას აძლევს აპს, წაიკითხოს და დაწეროს კონფიგურაცია „არ შემაწუხოთ“."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ნახვის ნებართვის გამოყენების დაწყება"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"მფლობელს საშუალებას აძლევს, დაიწყოს აპის ნებართვის გამოყენება. ჩვეულებრივი აპებისთვის არასოდეს უნდა იყოს საჭირო."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"მარტივი წვდომის მალსახმობის სამიზნე"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"აპს აძლევს მარტივი წვდომის მალსახმობის სამიზნის განსაზღვრის საშუალებას."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"აკონტროლეთ ეკრანის ბლოკირების პაროლებისა და PIN-ების სიმბოლოების სიგრძე."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ეკრანის განბლოკვის მცდელობების მონიტორინგი"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"მონიშნეთ რათა შეწყვიტოთ USB-ის გამართვა"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"რეჟიმი „გარემო ტესტირებისთვის“ ჩართულია"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"დააბრუნეთ ქარხნული პარამეტრები „გარემო ტესტირებისთვის“ რეჟიმის გასათიშად."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"სერიული კონსოლი ჩართულია"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"მუშაობა შეფერხებულია. გასათიშად მონიშნეთ ჩამტვირთავი."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB პორტში აღმოჩენილია სითხე ან ჭუჭყი"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB პორტი ავტომატურად გათიშულია. შეეხეთ დამატებითი ინფორმაციისთვის."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"თანხმობა USB პორტის გამოყენებაზე"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"კატეგორიის გარეშე"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ამ შეტყობინებების მნიშვნელობის დონე განისაზღვრა თქვენ მიერ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"მნიშვნელოვანია ჩართული მომხმარებლების გამო."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას (ამ ანგარიშის მქონე მომხმარებელი უკვე არსებობს)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"მიეცეს უფლება <xliff:g id="APP">%1$s</xliff:g>-ს <xliff:g id="ACCOUNT">%2$s</xliff:g>-ის მეშვეობით ახალი მომხმარებელი შექმნას?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ენის დამატება"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"რეგიონის პარამეტრები"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"აკრიფეთ ენის სახელი"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 81f512b..8fb6eb7 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Қолданбаға «Мазаламау» конфигурациясын оқу және жазу мүмкіндігін береді."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"рұқсаттарды пайдалану туралы деректерді көру"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Пайдаланушы қолданбаға берілетін рұқсаттарды басқара алады. Ондай рұқсаттар әдеттегі қолданбаларға керек емес."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"арнайы мүмкіндіктер таңбашасының мақсаты"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Қолданбаға арнайы мүмкіндіктер таңбашасының мақсатын анықтауға мүмкіндік береді."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Құпия сөз ережелерін тағайындау"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран бекітпесінің құпия сөздерінің және PIN кодтарының ұзындығын және оларда рұқсат етілген таңбаларды басқару."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Экран құлпын ашу әркеттерін бақылау"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB түзетуін өшіру үшін таңдаңыз."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Сынақ бағдарламасы режимі қосылды"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Сынақ бағдарламасы режимін өшіру үшін зауыттық күйіне қайтарыңыз."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Сериялық консоль қосылды"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Өнімділікке әсер етеді. Өшіру үшін жүктегішті тексеріңіз."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB портына сұйықтық немесе қоқыс кірді"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB порты автоматты түрде өшірілді. Толығырақ ақпарат алу үшін түртіңіз."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB портын пайдалана беруге болады"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Санатқа жатқызылмаған"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Сіз осы хабарландырулардың маңыздылығын орнатасыз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Қатысты адамдарға байланысты бұл маңызды."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы (мұндай есептік жазбаға ие пайдаланушы бұрыннан бар) жасауға рұқсат етілсін бе?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> қолданбасына <xliff:g id="ACCOUNT">%2$s</xliff:g> есептік жазбасы бар жаңа пайдаланушы жасауға рұқсат етілсін бе?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Тілді қосу"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Аймақ параметрі"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Тіл атауын теріңіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 539747b..6355289 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"អនុញ្ញាតឲ្យកម្មវិធីអាន និងសរសេរការកំណត់រចនាសម្ព័ន្ធមុខងារ កុំរំខាន។"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ចាប់ផ្ដើម​មើល​ការប្រើប្រាស់​ការអនុញ្ញាត"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"អនុញ្ញាត​ឱ្យម្ចាស់​ចាប់ផ្ដើម​ការប្រើប្រាស់​ការអនុញ្ញាត​សម្រាប់កម្មវិធី។ មិនគួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"គោលដៅផ្លូវកាត់ភាពងាយស្រួល"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"អនុញ្ញាតឱ្យ​កម្មវិធី​កំណត់​គោលដៅ​ផ្លូវកាត់​ភាពងាយស្រួល។"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់​ក្បួន​ពាក្យ​សម្ងាត់"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"គ្រប់គ្រងប្រវែង និងតួអក្សរដែលអនុញ្ញាតឲ្យប្រើក្នុងពាក្យសម្ងាត់ និងលេខសម្ងាត់ចាក់សោអេក្រង់។"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"តាមដាន​ការ​ព្យាយាម​ដោះ​សោ​អេក្រង់"</string>
@@ -1363,6 +1365,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ជ្រើស​រើស ដើម្បី​បិទ​ការ​កែ​កំហុសតាម USB ។"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"បាន​បើក​មុខងារប្រមូលធ្វើតេស្ត"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ធ្វើការកំណត់ដូចដើមឡើងវិញ ដើម្បី​បិទ​មុខងារប្រមូលធ្វើតេស្ត។"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"កុងសូល​ស៊េរី​ត្រូវបានបើក"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"ប្រតិបត្តិការ​ទទួលរង​ការប៉ះពាល់។ សូម​ពិនិត្យមើល​កម្មវិធី​ដំណើរការ​ប្រព័ន្ធ ដើម្បី​បិទ។"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"មានទឹក ឬ​កម្ទេចផ្សេងៗ​នៅក្នុងរន្ធ USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"រន្ធ USB ត្រូវបាន​បិទ​ដោយ​ស្វ័យប្រវត្តិ។ សូមចុច​ដើម្បី​ស្វែងយល់​បន្ថែម។"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"អាច​ប្រើរន្ធ USB បាន"</string>
@@ -1892,10 +1896,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"មិន​​បែងចែក​ប្រភេទ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"អ្នកបានកំណត់សារៈសំខាន់នៃការជូនដំណឹងទាំងនេះ"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"វាមានសារៈសំខាន់ដោយសារតែមនុស្សដែលពាក់ព័ន្ធ"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> (អ្នកប្រើប្រាស់ដែលមានគណនីនេះមានរួចហើយ) ដែរឬទេ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"អនុញ្ញាតឱ្យ <xliff:g id="APP">%1$s</xliff:g> បង្កើតអ្នកប្រើប្រាស់​ថ្មីដោយប្រើ <xliff:g id="ACCOUNT">%2$s</xliff:g> ដែរឬទេ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"បន្ថែមភាសា"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ចំណូលចិត្តតំបន់"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"វាយបញ្ចូលឈ្មោះភាសា"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index c7d0fea..7802129 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ಓದಲು ಮತ್ತು ಬರೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ವೀಕ್ಷಣಾ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ಆ್ಯಪ್‌ಗಾಗಿ ಅನುಮತಿ ಬಳಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್ ಟಾರ್ಗೆಟ್‌"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ಪ್ರವೇಶಿಸುವಿಕೆ ಶಾರ್ಟ್‌ಕಟ್ ಟಾರ್ಗೆಟ್‌ ಅನ್ನು ವಿವರಿಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ಪಾಸ್‌ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ಪರದೆ ಲಾಕ್‌ನಲ್ಲಿನ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಿನ್‌ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ಪರದೆಯ ಅನ್‌ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಿ"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ಸ್ವಯಂ ಪರೀಕ್ಷೆಯಾಗುವಿಕೆ ಮೋಡ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಫ್ಯಾಕ್ಟರಿ ರಿಸೆಟ್ ಮಾಡಬೇಕು."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"ಸರಣಿ ಕನ್ಸೋಲ್ ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"ಕಾರ್ಯಕ್ಷಮತೆಯ ಮೇಲೆ ಪರಿಣಾಮ ಬೀರುತ್ತದೆ. ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು, ಬೂಟ್‌ಲೋಡರ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ಪೋರ್ಟ್‌ನಲ್ಲಿ ದ್ರವ ಅಥವಾ ಧೂಳಿನ ಕಣಗಳಿವೆ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ಪೋರ್ಟ್ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB ಪೋರ್ಟ್ ಬಳಸಲು ಸರಿ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ವರ್ಗೀಕರಿಸದಿರುವುದು"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ನೀವು ಈ ಅಧಿಸೂಚನೆಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಿರುವಿರಿ."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ಜನರು ತೊಡಗಿಕೊಂಡಿರುವ ಕಾರಣ ಇದು ಅತ್ಯಂತ ಪ್ರಮುಖವಾಗಿದೆ."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (ಈ ಖಾತೆಯ ಬಳಕೆದಾರರು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿದ್ದಾರೆ) ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸಬೇಕೆ ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ಮೂಲಕ ಹೊಸ ಬಳಕೆದಾರರನ್ನು ರಚಿಸಲು <xliff:g id="APP">%1$s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ಭಾಷೆ ಸೇರಿಸಿ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c0dd8b1..72302c3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"앱에서 방해 금지 모드 설정을 읽고 작성하도록 허용합니다."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"권한 사용 보기 시작"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"앱의 권한 사용을 시작하려면 보유자를 허용하세요. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"접근성 단축키 대상"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"앱이 접근성 단축키 대상을 정의할 수 있도록 허용합니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"화면 잠금 비밀번호와 PIN에 허용되는 길이와 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"화면 잠금 해제 시도 모니터링"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"테스트 하네스 모드 사용 설정됨"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"테스트 하네스 모드를 사용 중지하려면 초기화하세요."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"시리얼 콘솔 사용 설정됨"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"성능에 영향을 미쳤습니다. 사용 중지하려면 부트로더를 확인하세요."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB 포트에서 액체 또는 이물질 감지됨"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB 포트가 자동으로 사용 중지되었습니다. 자세한 내용을 보려면 탭하세요."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB 포트를 사용해도 좋음"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"지정된 카테고리 없음"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"이러한 알림의 중요도를 설정했습니다."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"관련된 사용자가 있으므로 중요합니다."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까? 이 계정으로 등록된 사용자가 이미 존재합니다."</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g>에서 <xliff:g id="ACCOUNT">%2$s</xliff:g> 계정으로 신규 사용자를 만들도록 허용하시겠습니까?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"언어 추가"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"지역 환경설정"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"언어 이름 입력"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 9182563..09ee99c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Колдонмого \"Тынчымды алба\" режиминин конфигурациясын окуу жана жазуу мүмкүнчүлүгүн берет."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"уруксаттын колдонулушун көрүп баштоо"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Колдонмонун пайдаланылышына уруксат берүүгө мүмкүнчүлүк берет. Кадимки колдонмолорго эч качан талап кылынбашы керек."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"максаттуу атайын мүмкүнчүлүк аракетине кыска жол"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Колдонмого максаттуу атайын мүмкүнчүлүк аракетине кыска жолду аныктоого уруксат берет."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Сырсөз эрежелерин коюу"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран кулпусунун сырсөздөрү менен PIN\'дерине уруксат берилген узундук менен белгилерди көзөмөлдөө."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Экран кулпусун ачуу аракеттерин көзөмөлдөө"</string>
@@ -1363,6 +1365,8 @@
     <skip />
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Сыноо программасынын режими иштетилди"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Сериялык консоль иштетилди"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Майнаптуулугуна таасири тиет. Аны өчүрүү үчүн операциялык тутумду жүктөгүчтү текшериңиз."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB портунда суюктук же урандылар бар"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB порт автоматтык түрдө өчүрүлдү. Кененирээк маалымат алуу үчүн таптап коюңуз."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB портун колдонууга болот"</string>
@@ -1892,10 +1896,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Категорияларга бөлүнгөн эмес"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Бул эскертмелердин маанилүүлүгүн белгиледиңиз."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби (мындай аккаунту бар колдонуучу мурунтан эле бар)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> колдонмосуна <xliff:g id="ACCOUNT">%2$s</xliff:g> аккаунту менен жаңы колдонуучу түзүүгө уруксат бересизби?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Тил кошуу"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 0189c08..00bfc0e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"ອະນຸຍາດ​​ໃຫ້​ແອັບ​ອ່ານ​ ​ແລະ​ຂຽນການກນຳ​ດຄ່າ ບໍ່​ລົບ​ກວນ."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ເລີ່ມການໃຊ້ສິດອະນຸຍາດການເບິ່ງ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ອະນຸຍາດໃຫ້ຜູ້ຖືເລີ່ມການໃຊ້ສິດອະນຸຍາດສຳລັບແອັບໃດໜຶ່ງໄດ້. ແອັບປົກກະຕິບໍ່ຄວນຕ້ອງໃຊ້."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ເປົ້າໝາຍທາງລັດການຊ່ວຍເຂົ້າເຖິງ"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ອະນຸຍາດໃຫ້ແອັບລະບຸເປົ້າໝາຍທາງລັດການຊ່ວຍເຂົ້າເຖິງ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ຄວບຄຸມຄວາມຍາວ ແລະຕົວອັກສອນທີ່ອະ​ນຸ​ຍາດ​ໃຫ້​ຢູ່​ໃນລະ​ຫັດລັອກໜ້າຈໍ ແລະ PIN."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ເປີດໃຊ້ໂໝດ Test Harness ແລ້ວ"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ດຳເນີນການຣີເຊັດເປັນຄ່າຈາກໂຮງງານເພື່ອປິດການນຳໃຊ້ໂໝດ Test Harness."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"ເປີດນຳໃຊ້ຊີຣຽວຄອນໂຊແລ້ວ"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"ມີຜົນກະທົບກັບປະສິດທິພາບ. ເພື່ອປິດການນຳໃຊ້, ໃຫ້ກວດສອບ bootloader ເບິ່ງ."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"ມີຂອງແຫລວ ຫຼື ເສດດິນໃນຜອດ USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"ປິດຜອດ USB ໂດຍອັດຕະໂນມັດແລ້ວ. ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"ສາມາດໃຊ້ຜອດ USB ໄດ້"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ບໍ່​ມີ​ໝວດ​ໝູ່"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ທ່ານຕັ້ງຄວາມສຳຄັນຂອງການແຈ້ງເຕືອນເຫຼົ່ານີ້."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ຂໍ້ຄວາມນີ້ສຳຄັນເນື່ອງຈາກບຸກຄົນທີ່ກ່ຽວຂ້ອງ."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ່ (ມີຜູ້ໃຊ້ທີ່ໃຊ້ບັນຊີນີ້ຢູ່ກ່ອນແລ້ວ) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"ອະນຸຍາດໃຫ້ <xliff:g id="APP">%1$s</xliff:g> ສ້າງຜູ້ໃຊ້ໃໝ່ກັບ <xliff:g id="ACCOUNT">%2$s</xliff:g> ໄດ້ບໍ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ເພີ່ມພາສາ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ພິມຊື່ພາສາ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0d29c84..b615b24 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Leidžiama programai skaityti ir rašyti „Do Not Disturb“ konfigūraciją."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"pradėti peržiūrėti leidimo naudojimą"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Leidžia savininkui pradėti naudoti programos leidimą. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"pritaikomumo sparčiojo klavišo tikslas"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Programai leidžiama apibrėžti pritaikomumo sparčiojo klavišo tikslą."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Valdykite, kokio ilgio ekrano užrakto slaptažodžius ir PIN kodus galima naudoti."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Stebėti bandymus atrakinti ekraną"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pasirinkite, kas išjungtumėte USB derinimą."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Testavimo sistemos režimas įgalintas"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Atkurkite gamyklinius duomenis, kad išjungtumėte testavimo sistemos režimą."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serijos pultas įgalintas"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Našumas paveiktas. Norėdami išjungti, patikrinkite paleidyklę."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB prievade yra skysčių ar smulkių dalelių"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB prievadas automatiškai išjungtas. Palieskite, kad sužinotumėte daugiau."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Saugu naudoti USB prievadą"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Be kategorijos"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Galite nustatyti šių pranešimų svarbą."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Pridėkite kalbą"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiono nuostata"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 2547ba9..acc1430 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ļauj lietotnei lasīt un rakstīt režīma “Netraucēt” konfigurāciju."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"Datu skatīšana par izmantojamajām atļaujām"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Ļauj atļaujas īpašniekam sākt lietotnes atļauju izmantošanu. Parastām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"pieejamības īsinājumtaustiņa mērķis"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Ļauj lietotnei definēt pieejamības īsinājumtaustiņa mērķi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolēt ekrāna bloķēšanas paroļu un PIN garumu un tajos atļautās rakstzīmes."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -1383,6 +1385,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Atlasiet, lai atspējotu USB atkļūdošanu."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Drošības pārbaudes režīms ir iespējots"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Lai atspējotu drošības pārbaudes režīmu, veiciet rūpnīcas datu atiestatīšanu."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seriālā konsole ir iespējota"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Tiek ietekmēta veiktspēja. Lai atspējotu, pārbaudiet operētājsistēmu ielādes rīku."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB pieslēgvietā ir šķidrums vai daļiņas"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB pieslēgvieta ir automātiski atspējota. Pieskarieties, lai uzzinātu vairāk."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB pieslēgvietu drīkst izmantot"</string>
@@ -1924,10 +1928,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nav kategorijas"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Jūs iestatījāt šo paziņojumu svarīguma līmeni."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Tas ir svarīgi iesaistīto personu dēļ."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g> (lietotājs ar šādu kontu jau pastāv)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Vai atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> izveidot jaunu lietotāju, izmantojot e-pasta adresi <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Pievienot valodu"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Reģiona preference"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ierakstiet valodas nosaukumu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 9949eaa..761d965 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Дозволува апликацијата да чита и пишува конфигурација Не вознемирувај."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"започнете со користење на дозволата за приказ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Дозволува сопственикот да почне со користење на дозволата за апликација. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"цел на кратенката за пристапност"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Дозволува апликација да ја дефинира целта на кратенката за пристап."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Постави правила за лозинката"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролирај ги должината и знаците што се дозволени за лозинки и PIN-броеви за отклучување екран."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Следи ги обидите за отклучување на екранот"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изберете за да се оневозможи отстранување грешки на USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Овозможен е режимот на рамка за тестирање"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Извршете фабричко ресетирање за да го оневозможите режимот на рамка за тестирање."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Сериската конзола е овозможена"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Перформансите се засегнати. За да оневозможите, проверете го подигнувачот."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Течност или нечистотија во USB-портата"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-портата е автоматски оневозможена. Допрете за да дознаете повеќе."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Во ред е да се користи USB-порта"</string>
@@ -1893,10 +1897,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Некатегоризирано"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ја поставивте важноста на известувањава."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ова е важно заради луѓето кои се вклучени."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>? (Веќе постои корисник со оваа сметка.)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Дозволувате <xliff:g id="APP">%1$s</xliff:g> да создаде нов корисник со <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Додај јазик"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Претпочитувања за регион"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Внеси име на јазик"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index f711158..7876c29 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\'ശല്യപ്പെടുത്തരുത്\' കോൺഫിഗറേഷൻ വായിക്കുന്നതിനും എഴുതുന്നതിനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"അനുമതി ഉപയോഗം കാണാൻ ആരംഭിക്കുക"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ഒരു ആപ്പിനുള്ള അനുമതി ഉപയോഗം ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ഉപയോഗസഹായി കുറുക്കുവഴിയുടെ ടാർഗറ്റ്"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ഉപയോഗസഹായി കുറുക്കുവഴിയുടെ ടാർഗറ്റ് നിർവ്വചിക്കാൻ ആപ്പിനെ അനുവദിക്കുക."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"പാസ്‌വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"സ്‌ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ഡീബഗ്ഗുചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"പരിശോധനാ സംവിധാനങ്ങൾ മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"പരിശോധനാ സംവിധാന മോഡ് പ്രവർത്തനരഹിതമാക്കാൻ ഫാക്‌ടറി പുനഃക്രമീകരണം നിർവഹിക്കുക."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"സീരിയൽ കൺസോൾ പ്രവർത്തനക്ഷമമാക്കി"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"പ്രകടനത്തെ ബാധിച്ചു. പ്രവർത്തനരഹിതമാക്കാൻ, ബൂട്ട് ലോഡർ പരിശോധിക്കുക."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB പോർട്ടിൽ ദ്രാവകമോ പൊടിയോ കണ്ടെത്തി"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB പോർട്ടർ സ്വയമേവ പ്രവർത്തനരഹിതമായി. കൂടുതലറിയാൻ ടാപ്പ് ചെയ്യുക."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"ഇനി USB പോർട്ട് ഉപയോഗിക്കാം"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"വർഗ്ഗീകരിച്ചിട്ടില്ലാത്ത"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ഈ അറിയിപ്പുകളുടെ പ്രാധാന്യം നിങ്ങൾ സജ്ജീകരിച്ചു."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ഉൾപ്പെട്ടിട്ടുള്ള ആളുകളെ കണക്കിലെടുക്കുമ്പോള്‍ ഇത് പ്രധാനപ്പെട്ടതാണ്‌."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് (ഈ അക്കൗണ്ട് ഉപയോഗിക്കുന്ന ഒരു ഉപയോക്താവ് നിലവിലുണ്ട്) ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> എന്ന അക്കൗണ്ട് ഉപയോഗിച്ച് പുതിയ ഉപയോക്താവിനെ സൃഷ്‌ടിക്കാൻ <xliff:g id="APP">%1$s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ഒരു ഭാഷ ചേർക്കുക"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"മേഖലാ മുൻഗണന"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ഭാഷയുടെ പേര് ടൈപ്പുചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7570028..1a47403 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Апп-д Бүү саад бол тохируулгыг уншиж, бичихийг зөвшөөрөх"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"зөвшөөрлийн ашиглалтыг харж эхлэх"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Эзэмшигчид аппын зөвшөөрлөө ашиглаж эхлэхийг зөвшөөрдөг. Энгийн аппуудад шаардлагагүй."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"хандалтын товчлолын зорилт"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Аппад хандалтын товчлолын зорилтыг тодорхойлохыг зөвшөөрдөг."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Дэлгэц түгжих нууц үг болон ПИН кодны урт болон нийт тэмдэгтийн уртыг хянах."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Дэлгэцийн түгжээг тайлах оролдлогыг хянах"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Туршилтын цогц горимыг идэвхжүүлсэн"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Туршилтын цогц горимыг идэвхгүй болгохын тулд үйлдвэрийн төлөвт шинэчилнэ үү."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Цуваа консолыг идэвхжүүлсэн"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Гүйцэтгэлд нөлөөлнө. Идэвхгүй болгохын тулд эхэлж ачаалагчийг шалгана уу."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB порт дээрх шингэн зүйл эсвэл бохирдол"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB портыг автоматаар идэвхгүй болгосон байна. Дэлгэрэнгүй мэдээлэл авахын тулд товшино уу."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB портыг ашиглахад зүгээр"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Ангилаагүй"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Та эдгээр мэдэгдлийн ач холбогдлыг тогтоосон."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Оролцсон хүмүүсээс шалтгаалан энэ нь өндөр ач холбогдолтой."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай (ийм бүртгэлтэй хэрэглэгч аль хэдийн байна) шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g>-д <xliff:g id="ACCOUNT">%2$s</xliff:g>-тай шинэ хэрэглэгч үүсгэхийг зөвшөөрөх үү?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Хэл нэмэх"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Бүс нутгийн тохиргоо"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Улсын хэлийг бичнэ үү"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index e22bca0..05638df 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी अॅपला अनुमती देते."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"व्ह्यू परवानगी वापर सुरू करा"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"धारकास अ‍ॅपसाठी परवानगी वापरणे सुरू करण्याची अनुमती देते. सामान्य अ‍ॅप्ससाठी कधीही आवश्यकता नसते."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"अॅक्सेसिबिलिटी शॉर्टकट लक्ष्य"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"अ‍ॅपला अॅक्सेसिबिलिटी शॉर्टकट लक्ष्याबद्दल सांगण्यासाठी अनुमती द्या."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करा"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबगिंग बंद करण्यासाठी निवडा."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"टेस्ट हार्नेस मोड सुरू केला आहे"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"टेस्ट हार्नेस मोड बंद करण्यासाठी फॅक्टरी रीसेट करा."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"सिरीअल कन्सोल सुरू केला आहे"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"परफॉर्मन्सवर परिणाम होतो. बंद करण्यासाठी, बूटलोडर तपासा."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB पोर्ट मध्ये ओलावा किंवा धूळ आहे"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB पोर्ट आपोआप बंद होईल. अधिक जाणून घेण्यासाठी टॅप करा."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB पोर्ट वापरण्यासाठी ठीक आहे"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"वर्गीकरण न केलेले"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"तुम्ही या सूचनांचे महत्त्व सेट केले."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"सामील असलेल्या लोकांमुळे हे महत्वाचे आहे."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची (हे खाते असलेला वापरकर्ता आधीपासून अस्तित्वात आहे) <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> सह नवीन वापरकर्ता तयार करण्याची <xliff:g id="APP">%1$s</xliff:g> ला अनुमती द्यायची आहे का?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"एक भाषा जोडा"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"प्रदेश प्राधान्य"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषा नाव टाइप करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 35e3658..d5c5475 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Membenarkan apl membaca dan menulis konfigurasi Jangan Ganggu."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"mulakan lihat penggunaan kebenaran"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Membenarkan pemegang memulakan penggunaan kebenaran untuk apl. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"sasaran pintasan kebolehaksesan"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Membenarkan apl mentakrifkan sasaran pintasan kebolehaksesan."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan  dan PIN kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Pantau percubaan buka kunci skrin"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk melumpuhkan penyahpepijatan USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Mod Abah-abah Ujian didayakan"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Laksanakan tetapan semula kilang untuk melumpuhkan Mod Abah-abah Ujian."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Konsol bersiri didayakan"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Prestasi terjejas. Untuk melumpuhkan, semak pemuat but."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Cecair atau serpihan dalam port USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Port USB dilumpuhkan secara automatik. Ketik untuk mengetahui lebih lanjut."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"OK untuk menggunakan port USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Tidak dikategorikan"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Anda menetapkan kepentingan pemberitahuan ini."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mesej ini penting disebabkan orang yang terlibat."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g> (Pengguna dengan akaun ini sudah wujud) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Benarkan <xliff:g id="APP">%1$s</xliff:g> membuat Pengguna baharu dengan <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Tambahkan bahasa"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Pilihan wilayah"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Taipkan nama bahasa"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index d69b7d1..5506166 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"မနှောင့်ယှက်ရန် ချိန်ညှိမှုကို အပ်ဖ်များ ဖတ်ခြင်း ပြင်ခြင်းပြုလုပ်နိုင်ရန် ခွင့်ပြုမည်။"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"အစမြင်ကွင်း ခွင့်ပြုချက် အသုံးပြုမှု"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"အက်ပ်တစ်ခုအတွက် ခွင့်ပြုချက်စတင်အသုံးပြုမှုကို ကိုင်ဆောင်သူအား ခွင့်ပြုသည်။ ပုံမှန်အက်ပ်များအတွက် ဘယ်သောအခါမျှ မလိုအပ်ပါ။"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ် ပစ်မှတ်"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"အများသုံးစွဲနိုင်မှု ဖြတ်လမ်းလင့်ခ် ပစ်မှတ်ကို အက်ပ်အား သတ်မှတ်ခွင့်ပြုသည်။"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"စကားဝှက်စည်းမျဥ်းကိုသတ်မှတ်ရန်"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက်များနှင့် PINများရှိ ခွင့်ပြုထားသည့် စာလုံးအရေအတွက်နှင့် အက္ခရာများအား ထိန်းချုပ်ရန်။"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"မျက်နှာပြင်လော့ခ်ဖွင့်ရန် ကြိုးပမ်းမှုများကို စောင့်ကြည့်ပါ"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ဖြင့် အမှားရှာပြင်ခြင်းကို ပိတ်ရန် ရွေးပါ။"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"\'စမ်းသပ်ခြင်းစနစ်မုဒ်\' ဖွင့်ထားသည်"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"\'စမ်းသပ်ခြင်းစနစ် မုဒ်\' ကိုပိတ်ရန် စက်ရုံထုတ်အတိုင်း ပြင်ဆင်သတ်မှတ်ပါ။"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"အမှတ်စဉ် ကွန်ဆိုးလ်ကို ဖွင့်ထားသည်"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"စွမ်းဆောင်ရည်အပေါ် သက်ရောက်မှုရှိနိုင်ပါသည်။ ပိတ်ရန် bootloader ကို စစ်ဆေးပါ။"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ပို့တ်တွင် အရည် သို့မဟုတ် အမှိုက်စ ရှိနေသည်"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ပို့တ်ကို အလိုအလျောက် ပိတ်ထားသည်။ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB ပို့တ်ကို အသုံးပြုနိုင်သည်"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"အမျိုးအစားမခွဲရသေးပါ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ဤသတိပေးချက်များ၏ အရေးပါမှုကိုသတ်မှတ်ပြီးပါပြီ။"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ပါဝင်သည့်လူများကြောင့် အရေးပါပါသည်။"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား (ဤအကောင့်ဖြင့် အသုံးပြုသူ ရှိနှင့်ပြီးဖြစ်သည်) ။"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> ဖြင့်အသုံးပြုသူအသစ်ကို <xliff:g id="APP">%1$s</xliff:g> အား ဖန်တီးခွင့်ပြုလိုပါသလား ။"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ဘာသာစကားတစ်ခု ထည့်ပါ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ဒေသရွေးချယ်မှု"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ဘာသာစကားအမည် ထည့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a597170..f6bbaaa 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -226,7 +226,7 @@
     <string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
     <string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
-    <string name="global_action_emergency" msgid="7112311161137421166">"Nødsituasjon"</string>
+    <string name="global_action_emergency" msgid="7112311161137421166">"Nødssituasjon"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
     <string name="global_action_logout" msgid="935179188218826050">"Avslutt økten"</string>
     <string name="global_action_screenshot" msgid="8329831278085426283">"Skjermdump"</string>
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Lar appen lese og skrive konfigurasjon av Ikke forstyrr."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"start visning av bruk av tillatelser"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Lar innehaveren starte bruk av tillatelser for en app. Dette skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"mål for tilgjengelighetssnarvei"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Tillat at en app definerer målet for tilgjengelighetssnarveien."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollerer tillatt lengde og tillatte tegn i passord og PIN-koder for opplåsing av skjermen."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Overvåk forsøk på å låse opp skjermen"</string>
@@ -815,7 +817,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Trykk på menyknappen for å låse opp."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Tegn mønster for å låse opp"</string>
-    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Nødsituasjon"</string>
+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Nødssituasjon"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Tilbake til samtale"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Riktig!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Prøv på nytt"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Velg for å deaktivere USB-debugging."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Testrammeverk-modus er slått på"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Tilbakestill enheten til fabrikkstandard for å slå av Testrammeverk-modus."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seriekonsollen er aktivert"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ytelsen er påvirket. Sjekk oppstartsinnlasteren for å deaktivere."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Væske eller rusk i USB-porten"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-porten deaktiveres automatisk. Trykk for å finne ut mer."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Trygt å bruke USB-porten"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Uten kategori"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du angir viktigheten for disse varslene."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dette er viktig på grunn av folkene som er involvert."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g> (en bruker med denne kontoen eksisterer allerede)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Vil du la <xliff:g id="APP">%1$s</xliff:g> opprette en ny bruker med <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Legg til et språk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regionsinnstilling"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Skriv inn språknavn"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 0cbaaa0..c560822 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्‍नको लागि अनुप्रयोगलाई अनुमति दिनुहोस्।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"वाहकलाई कुनै अनुप्रयोगसम्बन्धी अनुमतिको प्रयोग सुरु गर्न दिन्छ। साधारण अनुप्रयोगहरूलाई कहिल्यै आवश्यक नपर्नु पर्ने हो।"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"पहुँचसम्बन्धी सर्टकटको लक्ष्य"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"कुनै अनुप्रयोगलाई पहुँचसम्बन्धी सर्टकटको लक्ष्य परिभाषित गर्न दिन्छ।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"मनिटरको स्क्रिन अनलक गर्ने प्रयासहरू"</string>
@@ -1367,6 +1369,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डिबगिङलाई असक्षम पार्न ट्याप गर्नुहोस्।"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"परीक्षण प्याकेज मोड सक्षम पारियो"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"परीक्षण प्याकेज मोड असक्षम पार्न फ्याक्ट्री रिसेट गर्नुहोस्।"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"क्रमसम्बन्धी कन्सोल सक्षम पारियो"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"कार्यसम्पादनमा प्रभाव परेको छ। यसलाई असक्षम पार्न बुटलोडरको जाँच गर्नुहोस्।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB पोर्टमा तरल पदार्थ वा धुलो भएको कुरा पत्ता लाग्यो"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB पोर्ट स्वतः असक्षम पारियो। थप जान्न ट्याप गर्नुहोस्।"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB पोर्ट प्रयोग गर्दा हुन्छ"</string>
@@ -1896,10 +1900,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"वर्गीकरण नगरिएको"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"तपाईंले यी सूचनाहरूको महत्त्व सेट गर्नुहोस् ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"यसमा सङ्लग्न भएका मानिसहरूको कारणले गर्दा यो महत्वपूर्ण छ।"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> (यस खाताको प्रयोगकर्ता पहिले नै अवस्थित छ) मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> मा नयाँ प्रयोगकर्ता सिर्जना गर्न <xliff:g id="APP">%1$s</xliff:g> लाई अनुमति दिने हो?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"भाषा थप्नुहोस्"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"क्षेत्रको प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"भाषाको नाम टाइप गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index e898389..6dc5a64 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Hiermee kan de app configuratie voor Niet storen lezen en schrijven."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"rechtengebruik starten"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Hiermee kan de houder het rechtengebruik voor een app starten. Nooit vereist voor normale apps."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"doel van snelkoppeling voor toegankelijkheid"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Hiermee kan een app het doel van de snelkoppeling voor toegankelijkheid definiëren."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"De lengte en het aantal tekens beheren die zijn toegestaan in wachtwoorden en pincodes voor schermvergrendeling."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test harness-modus is ingeschakeld"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Reset de fabrieksinstellingen om de test harness-modus uit te schakelen."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seriële console ingeschakeld"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Dit is van invloed op de prestaties. Controleer de bootloader om dit uit te schakelen."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Vloeistof of vuil in USB-poort"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-poort is automatisch uitgeschakeld. Tik voor meer informatie."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-poort kan worden gebruikt"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Geen categorie"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Je stelt het belang van deze meldingen in."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Dit is belangrijk vanwege de betrokken mensen."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt (er is al een gebruiker met dit account)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Toestaan dat <xliff:g id="APP">%1$s</xliff:g> een nieuwe gebruiker met <xliff:g id="ACCOUNT">%2$s</xliff:g> maakt?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Een taal toevoegen"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiovoorkeur"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Typ een taalnaam"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bd6d2cc..bc3c400 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" କନଫିଗରେଶନ୍‍ ପଢ଼ିବା ତଥା ଲେଖିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ଅନୁମତି ବ୍ୟବହାର ଦେଖିବା ଆରମ୍ଭ କରନ୍ତୁ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ଏକ ଆପ୍ ପାଇଁ ଅନୁମତିର ବ୍ୟବହାର ଆରମ୍ଭ କରିବାକୁ ଧାରକକୁ ଅନୁମତି ଦେଇଥାଏ। ସାଧାରଣ ଆପ୍‌ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍ ଟାର୍ଗେଟ୍"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ଆକ୍ସେସିବିଲିଟୀ ସର୍ଟକଟ୍ ଟାର୍ଗେଟ୍ ବ୍ୟାଖ୍ୟା କରିବା ପାଇଁ ଯେ କୌଣସି ଆପ୍‍କୁ ଅନୁମତି ଦିଏ।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ପାସ୍‌ୱର୍ଡ ନିୟମାବଳୀ ସେଟ୍ କରନ୍ତୁ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ଲକ୍‍ ସ୍କ୍ରୀନ୍‍ ପାସ୍‌ୱର୍ଡ ଓ PINରେ ଅନୁମୋଦିତ ଦୀର୍ଘତା ଓ ବର୍ଣ୍ଣ ନିୟନ୍ତ୍ରଣ କରନ୍ତୁ।"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ସ୍କ୍ରୀନ୍-ଅନଲକ୍ କରିବା ଉଦ୍ୟମ ନୀରିକ୍ଷଣ କରନ୍ତୁ"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ସକ୍ଷମ ଅଛି"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ଟେଷ୍ଟ ହାର୍‌ନେସ୍ ମୋଡ୍ ଅକ୍ଷମ କରିବାକୁ ଏକ ଫ୍ୟାକ୍ଟରୀ ରିସେଟ୍ କରନ୍ତୁ।"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"କ୍ରମିକ କନ୍‍‍ସୋଲ୍‍କୁ ସକ୍ଷମ କରାଯାଇଛି"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"କାର୍ଯ୍ୟଦକ୍ଷତା ପ୍ରଭାବିତ ହୋଇଛି। ଅକ୍ଷମ କରିବା ପାଇଁ, ବୁଟ୍‌ଲୋଡର୍‍ର ଯାଞ୍ଚ କରନ୍ତୁ।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ପୋର୍ଟରେ ତରଳ ପଦାର୍ଥ ବା ଧୂଳି"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ପୋର୍ଟ ସ୍ୱଚାଳିତ ଭାବେ ଅକ୍ଷମ ହୋଇଛି। ଅଧିକ ଜାଣିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB ପୋର୍ଟ ବ୍ୟବହାର କରିବା ପାଇଁ ଠିକ୍ ଅଟେ"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ଅବର୍ଗୀକୃତ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକର ପ୍ରମୁଖତା ଆପଣ ସେଟ୍‍ କରନ୍ତି।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ସମ୍ପୃକ୍ତ ଲୋକଙ୍କ କାରଣରୁ ଏହା ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ଅଟେ।"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ (ପୂର୍ବରୁ ଏହି ଆକାଉଣ୍ଟ ଉପଯୋଗକର୍ତ୍ତାଙ୍କ ନାମରେ ଅଛି) ଅନୁମତି ଦେବେ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g>ରେ ଏକ ନୂଆ ଉପଯୋଗକର୍ତ୍ତା ତିଆରି କରିବା ପାଇଁ <xliff:g id="ACCOUNT">%2$s</xliff:g>କୁ ଅନୁମତି ଦେବେ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ଏକ ଭାଷା ଯୋଡ଼ନ୍ତୁ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ଭାଷାର ନାମ ଟାଇପ୍‍ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index a9e93d4..74deed1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"ਐਪ ਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ਧਾਰਕ ਨੂੰ ਕਿਸੇ ਹੋਰ ਐਪ ਲਈ ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਦਿੰਦਾ ਹੈ। ਸਧਾਰਨ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਵੇਗਾ।"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਟੀਚਾ"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ਕਿਸੇ ਐਪ ਨੂੰ ਪਹੁੰਚਯੋਗਤਾ ਸ਼ਾਰਟਕੱਟ ਟੀਚੇ ਨੂੰ ਪਰਿਭਾਸ਼ਿਤ ਕਰਨ ਦਿਓ।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ਪਾਸਵਰਡ ਨਿਯਮ ਸੈੱਟ ਕਰੋ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ਸਕ੍ਰੀਨ ਲਾਕ ਪਾਸਵਰਡਾਂ ਅਤੇ ਪਿੰਨ ਵਿੱਚ ਆਗਿਆ ਦਿੱਤੀ ਲੰਮਾਈ ਅਤੇ ਅੱਖਰਾਂ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ।"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ਸਕ੍ਰੀਨ ਅਣਲਾਕ ਕਰਨ ਦੀਆਂ ਕੋਸ਼ਿਸ਼ਾਂ \'ਤੇ ਨਿਗਰਾਨੀ ਰੱਖੋ"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ਡੀਬੱਗਿੰਗ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਚੁਣੋ।"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਚਾਲੂ ਹੈ"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ਟੈਸਟ ਹਾਰਨੈੱਸ ਮੋਡ ਬੰਦ ਕਰਨ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ।"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"ਸੀਰੀਅਲ ਕੰਸੋਲ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"ਕਾਰਗੁਜ਼ਾਰੀ ਪ੍ਰਭਾਵਿਤ ਹੋਈ ਹੈ। ਬੰਦ ਕਰਨ ਲਈ, ਬੂਟਲੋਡਰ ਦੇਖੋ।"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB ਪੋਰਟ ਵਿੱਚ ਪਾਣੀ ਜਾਂ ਧੂੜ-ਮਿੱਟੀ"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB ਪੋਰਟ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਬੰਦ ਕੀਤਾ ਗਿਆ। ਹੋਰ ਜਾਣਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB ਪੋਰਟ ਵਰਤਣ ਲਈ ਠੀਕ ਹੈ"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ਗੈਰ-ਸ਼੍ਰੇਣੀਕਿਰਤ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ਤੁਸੀਂ ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਦੀ ਮਹੱਤਤਾ ਸੈੱਟ ਕੀਤੀ।"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ਇਹ ਸ਼ਾਮਲ ਲੋਕਾਂ ਦੇ ਕਾਰਨ ਮਹੱਤਵਪੂਰਨ ਹੈ।"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ (ਇਸ ਖਾਤੇ ਨਾਲ ਇੱਕ ਵਰਤੋਂਕਾਰ ਪਹਿਲਾਂ ਤੋਂ ਹੀ ਮੌਜੂਦ ਹੈ)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"ਕੀ <xliff:g id="APP">%1$s</xliff:g> ਨੂੰ <xliff:g id="ACCOUNT">%2$s</xliff:g> ਨਾਲ ਨਵਾਂ ਵਰਤੋਂਕਾਰ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣੀ ਹੈ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ਇੱਕ ਭਾਸ਼ਾ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ਖੇਤਰ ਤਰਜੀਹ"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"ਭਾਸ਼ਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 537089c..b1369c7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Pozwala aplikacji na odczyt i zmianę konfiguracji trybu Nie przeszkadzać."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"rozpocząć wyświetlanie użycia uprawnień"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Umożliwia rozpoczęcie korzystania z uprawnienia dotyczącego danej aplikacji jego posiadaczowi. Zwykłe aplikacje nie powinny potrzebować tego uprawnienia."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cel skrótu do ułatwień dostępu"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Pozwala aplikacji definiować cel skrótu do ułatwień dostępu."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolowanie długości haseł blokady ekranu i kodów PIN oraz dozwolonych w nich znaków."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitorowanie prób odblokowania ekranu"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Tryb jarzma testowego został włączony"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Przywróć ustawienia fabryczne, by wyłączyć tryb jarzma testowego."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Konsola szeregowa włączona"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Wpływa na wydajność. Aby wyłączyć, sprawdź program rozruchowy."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Wilgoć lub brud w porcie USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Port USB został automatycznie wyłączony. Kliknij, by dowiedzieć się więcej."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Możesz używać portu USB"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Bez kategorii"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ustawiłeś ważność tych powiadomień."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ta wiadomość jest ważna ze względu na osoby uczestniczące w wątku."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g> (użytkownik dla tego konta już istnieje)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Zezwolić aplikacji <xliff:g id="APP">%1$s</xliff:g> na utworzenie nowego użytkownika dla konta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dodaj język"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Ustawienie regionu"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Wpisz nazwę języka"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ba8285f..4dc2700 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permitir que o app leia e grave a configuração \"Não perturbe\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar uso da permissão para visualização"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite que o sistema inicie o uso de permissão para um app. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"objetivo do atalho de acessibilidade"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite que um app defina o objetivo do atalho de acessibilidade."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitorar tentativas de desbloqueio de tela"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modo Arcabouço de testes ativado"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Console serial ativado"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"O desempenho foi impactado. Para desativar, verifique o carregador de inicialização."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Líquido ou detrito na porta USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"A porta USB é desativada automaticamente. Toque para saber mais."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"É seguro usar a porta USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sem classificação"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c7df3a7..141dca3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -229,7 +229,7 @@
     <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
     <string name="global_action_logout" msgid="935179188218826050">"Terminar sessão"</string>
-    <string name="global_action_screenshot" msgid="8329831278085426283">"Captura de ecrã"</string>
+    <string name="global_action_screenshot" msgid="8329831278085426283">"Capt. ecrã"</string>
     <string name="bugreport_title" msgid="5981047024855257269">"Relatório de erro"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Relatório interativo"</string>
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite à aplicação ler e alterar a configuração de Não incomodar"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar utilização da autorização de visualização"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite que o titular inicie a utilização de autorizações para uma aplicação. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"alvo do atalho de acessibilidade"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite a uma aplicação definir o alvo do atalho de acessibilidade."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlar o comprimento e os carateres permitidos nos PINs e nas palavras-passe do bloqueio de ecrã."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração por USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modo de estrutura de teste ativado"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Efetue uma reposição de dados de fábrica para desativar o Modo de estrutura de teste."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Consola de série ativada"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"O desempenho é afetado. Para desativar, selecione o carregador de arranque."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Líquido ou resíduos na porta USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"A porta USB é automaticamente desativada. Toque para saber mais."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"É seguro utilizar a porta USB"</string>
@@ -1508,7 +1512,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"Eliminar os itens"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Anular as eliminações"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Não fazer nada por agora"</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"Selecionar uma conta"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"Selecione uma conta"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Adicionar uma conta"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Adicionar conta"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Aumentar"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sem categoria"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Definiu a importância destas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"É importante devido às pessoas envolvidas."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Intr. nome do idioma"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ba8285f..4dc2700 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permitir que o app leia e grave a configuração \"Não perturbe\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"iniciar uso da permissão para visualização"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite que o sistema inicie o uso de permissão para um app. Não deve ser necessário para apps comuns."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"objetivo do atalho de acessibilidade"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite que um app defina o objetivo do atalho de acessibilidade."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitorar tentativas de desbloqueio de tela"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modo Arcabouço de testes ativado"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Console serial ativado"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"O desempenho foi impactado. Para desativar, verifique o carregador de inicialização."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Líquido ou detrito na porta USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"A porta USB é desativada automaticamente. Toque para saber mais."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"É seguro usar a porta USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Sem classificação"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Você definiu a importância dessas notificações."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Isso é importante por causa das pessoas envolvidas."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um usuário com essa conta)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Permitir que o app <xliff:g id="APP">%1$s</xliff:g> crie um novo usuário com <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Adicionar um idioma"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Digitar nome do idioma"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 7277228..73f31c4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Permite aplicației să citească și să scrie configurația Nu deranja."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"porniți folosirea permisiunii de vizualizare"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Permite proprietarului să pornească folosirea permisiunii pentru o aplicație. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ținta comenzii rapide de accesibilitate"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Permite unei aplicații să definească ținta comenzii rapide de accesibilitate."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Să seteze reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Să monitorizeze încercările de deblocare a ecranului"</string>
@@ -1383,6 +1385,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selectați pentru a dezactiva remedierea erorilor prin USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modul Set de testare este activat"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Reveniți la setările din fabrică pentru a dezactiva modul Set de testare."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Consola din serie este activată"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performanța este afectată. Pentru a dezactiva, verificați programul bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Lichide sau reziduuri în portul USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Portul USB este dezactivat automat. Atingeți ca să aflați mai multe."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Portul USB poate fi folosit"</string>
@@ -1924,10 +1928,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Neclasificate"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Dvs. setați importanța acestor notificări."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Notificarea este importantă având în vedere persoanele implicate."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>? (există deja un utilizator cu acest cont)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Permiteți ca <xliff:g id="APP">%1$s</xliff:g> să creeze un nou utilizator folosind <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Adăugați o limbă"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiunea preferată"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Numele limbii"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e458e46..9e43592 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Открывает приложению доступ к настройкам режима \"Не беспокоить\" и позволяет изменять их."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"Просмотр данных об используемых разрешениях"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Приложение получит доступ к данным об используемых разрешениях. Это разрешение не требуется обычным приложениям."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"Цель быстрого включения"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Приложение сможет определять цель быстрого включения."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Настройка правил для паролей"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролировать длину и символы при вводе пароля и PIN-кода."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Отслеживание попыток разблокировать экран"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Нажмите, чтобы отключить отладку по USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Тестовый режим включен"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Чтобы отключить тестовый режим, сбросьте настройки до заводских."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Консоль последовательного порта включена"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Производительность устройства снижена. Чтобы отключить консоль, перейдите в загрузчик операционной системы."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"В USB-порт попала вода или грязь"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-порт был автоматически отключен. Нажмите, чтобы узнать подробности."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB-порт можно использовать"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Без категории"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Вы определяете важность этих уведомлений."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важное (люди)"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g> (пользователь с этим аккаунтом уже существует)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Разрешить приложению \"<xliff:g id="APP">%1$s</xliff:g>\" создать нового пользователя с аккаунтом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Добавьте язык"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Региональные настройки"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Введите язык"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 3e0f582..cc2a2a89 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"බාධා නොකරන්න වින්‍යාස කිරීම කියවීමට සහ ලිවීමට යෙදුමට ඉඩ දෙයි."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"අවසර භාවිතය බැලීමට ආරම්භ කරන්න"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"තබා සිටින්නාට යෙදුමක් සඳහා අවසර භාවිතය ආරම්භ කිරීමට ඉඩ දෙයි. සාමාන්‍ය යෙදුම් සඳහා කිසි විටෙක අවශ්‍ය නොවිය යුතු ය."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ප්‍රවේශ්‍යතා කෙටිමං ඉලක්කය"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ප්‍රවේශ්‍යතා කෙටිමං ඉලක්කය නිර්වචනය කිරීමට යෙදුමකට ඉඩ දෙන්න."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"මුරපද නීති සකස් කිරීම"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"තිර අගුලු මුරපද සහ PIN තුළ ඉඩ දෙන දිග සහ අනුලකුණු පාලනය කිරීම."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string>
@@ -1363,6 +1365,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB නිදොස්කරණය අබල කිරීමට තෝරන්න."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"පුරක පරීක්‍ෂා ප්‍රකාරය සබලයි"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"පුරක පරීක්‍ෂා ප්‍රකාරය අබල කිරීමට කර්මාන්තශාලා යළි සැකසීමක් ඉටු කරන්න."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"අනුක්‍රමික කොන්සෝලය සබලයි"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"කාර්ය සාධනය බලපෑමට ලක් වී ඇත. අබල කිරීමට, ආරම්භකය පරීක්ෂා කරන්න."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB තොට තුළ ද්‍රව හෝ කුණු"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB තොට ස්වයංක්‍රීයව අබල කෙරේ. තවත් දැන ගැනීමට තට්ටු කරන්න."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB තොට භාවිත කළාට කමක් නැත"</string>
@@ -1892,10 +1896,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"වර්ගීකරණය නොකළ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ඔබ මෙම දැනුම්දීම්වල වැදගත්කම සකසා ඇත."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"සම්බන්ධ වූ පුද්ගලයන් නිසා මෙය වැදගත් වේ."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද (මෙම ගිණුම සහිත පරිශීලකයෙකු දැනටමත් සිටී) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> හට <xliff:g id="ACCOUNT">%2$s</xliff:g> සමගින් නව පරිශීලකයෙකු සෑදීමට ඉඩ දෙන්නද ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"භාෂාවක් එක් කරන්න"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ප්‍රදේශ මනාපය"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"භාෂා නම ටයිප් කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 015cd91..0e49c86 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Umožňuje aplikácii čítať a zapisovať konfiguráciu režimu bez vyrušení."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"spustenie používania povolenia na zobrazenie"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Umožňuje držiteľovi spustiť používanie povolenia aplikáciou. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cieľ skratky dostupnosti"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Umožňuje aplikácii definovať cieľ skratky dostupnosti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nastavte dĺžku hesiel na odomknutie obrazovky aj kódov PIN a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Sledovanie pokusov o odomknutie obrazovky"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, ak chcete zakázať ladenie cez USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Režim správcu testov je aktivovaný"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Ak chcete zakázať režim správcu testov, obnovte výrobné nastavenia."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Sériová konzola je povolená"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ovplyvňuje výkon. Ak ju chcete zakázať, skontrolujte zavádzací program systému."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Tekutina alebo nečistoty v porte USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Port USB je automaticky deaktivovaný. Ďalšie informácie zobrazíte klepnutím."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Port USB môžete použiť"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nekategorizované"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Nastavili ste dôležitosť týchto upozornení."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Táto správa je dôležitá vzhľadom na osoby, ktorých sa to týka."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g> (používateľ s týmto účtom už existuje)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Chcete povoliť aplikácii <xliff:g id="APP">%1$s</xliff:g> vytvoriť nového používateľa pomocou účtu <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Pridať jazyk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferovaný región"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Zadajte názov jazyka"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 54da1dc..8340046 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Aplikaciji omogoča branje in pisanje konfiguracije načina »ne moti«."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"začetek uporabe dovoljenja za ogledovanje"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Imetniku omogoča začetek uporabe dovoljenj za aplikacijo. Nikoli ni potrebno za navadne aplikacije."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"cilj bližnjice funkcije za ljudi s posebnimi potrebami"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Aplikaciji dovoljuje, da določi cilj bližnjice funkcije za ljudi s posebnimi potrebami."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih in kodah PIN za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Nadzor nad poskusi odklepanja zaslona"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Način preizkusnega ogrodja je omogočen"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Če želite onemogočiti način preizkusnega ogrodja, ponastavite napravo na tovarniške nastavitve."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Serijska konzola je omogočena"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Učinkovitost delovanja je slabša. Uporabo konzole lahko onemogočite v zagonskem nalagalniku."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"V vratih USB je tekočina ali umazanija"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Vrata USB so samodejno onemogočena. Dotaknite se, če želite izvedeti več."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Vrata USB so varna za uporabo"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Nekategorizirano"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Vi določite raven pomembnosti teh obvestil."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Pomembno zaradi udeleženih ljudi."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g> (uporabnik s tem računom že obstaja)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Ali aplikaciji <xliff:g id="APP">%1$s</xliff:g> dovolite, da ustvari novega uporabnika za račun <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dodajanje jezika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Nastavitev območja"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Vnesite ime jezika"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 48ae4d7..411d458 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Lejon aplikacionin të lexojë dhe shkruajë konfigurimin e \"Mos shqetëso\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"nis përdorimin e lejes për shikimin"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Lejon që mbajtësi të nisë përdorimin e lejeve për një aplikacion. Nuk duhet të nevojitet asnjëherë për aplikacionet normale."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"objektivi i shkurtores së qasshmërisë"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Lejon që një aplikacion të përcaktojë objektivin e shkurtores së qasshmërisë."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Cakto rregullat e fjalëkalimit"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollo gjatësinë dhe karakteret e lejuara në fjalëkalimet dhe kodet PIN të kyçjes së ekranit."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Monitoro tentativat e shkyçjes së ekranit"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Përzgjidhe për të çaktivizuar korrigjimin e gabimeve të USB-së"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Modaliteti i lidhjes së testimit është aktivizuar"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Kryej një rivendosje në cilësimet e fabrikës për të çaktivizuar \"Modalitetin e lidhjes së testimit\"."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Paneli komandues i serisë është aktivizuar"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ndikohet cilësia e funksionimit. Për ta çaktivizuar, kontrollo ngarkuesin e sistemit."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Lëngje ose papastërti në portën e USB-së"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Porta e USB-së është çaktivizuar automatikisht. Trokit për të mësuar më shumë."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Në rregulloj për përdorimin e portës USB"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"E pakategorizuara"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ke caktuar rëndësinë e këtyre njoftimeve."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Është i rëndësishëm për shkak të personave të përfshirë."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> (një përdorues me këtë llogari ekziston tashmë) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Të lejohet <xliff:g id="APP">%1$s</xliff:g> që të krijojë një përdorues të ri me <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Shto një gjuhë"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Preferenca e rajonit"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Shkruaj emrin e gjuhës"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 75fc1ce..c2d636d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -27,7 +27,7 @@
     <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"PB"</string>
     <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
-    <string name="untitled" msgid="4638956954852782576">"&lt;Без наслова&gt;"</string>
+    <string name="untitled" msgid="4638956954852782576">"&lt;Без имена&gt;"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Нема броја телефона)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Непознато"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Гласовна пошта"</string>
@@ -658,6 +658,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Дозвољава апликацији да чита и уписује конфигурацију подешавања Не узнемиравај."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"почетак коришћења дозволе за преглед"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Дозвољава власнику да започне коришћење дозволе за апликацију. Никада не би требало да буде потребна за уобичајене апликације."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"циљ пречице за приступачност"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Дозвољава апликацији да дефинише циљ пречице за приступачност."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролише дужину и знакове дозвољене у лозинкама и PIN-овима за закључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Надгледајте покушаје откључавања екрана"</string>
@@ -1383,6 +1385,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Омогућен је режим пробног коришћења"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Обавите ресетовање на фабричка подешавања да бисте онемогућили режим пробног коришћења."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Серијска конзола је омогућена"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Учинак је смањен. Да бисте онемогући конзолу, проверите покретачки програм."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Течност или нечистоћа у USB порту"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB порт је аутоматски искључен. Додирните да бисте сазнали више."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Коришћење USB порта је дозвољено"</string>
@@ -1924,10 +1928,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Некатегоризовано"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ви подешавате важност ових обавештења."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Ово је важно због људи који учествују."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g> (корисник са тим налогом већ постоји)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Желите ли да дозволите да <xliff:g id="APP">%1$s</xliff:g> направи новог корисника са налогом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Додајте језик"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Подешавање региона"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Унесите назив језика"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index fdd0b7b..854e44f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ger appen läs- och skrivbehörighet till konfigurationen för Stör ej."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"börja visa behörighetsanvändningen"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Gör att innehavaren kan öppna behörighetsanvändning för en app. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"mål för Aktivera tillgänglighet snabbt"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Tillåter att en app kan definiera målet för Aktivera tillgänglighet snabbt."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Styr tillåten längd och tillåtna tecken i lösenord och pinkoder för skärmlåset."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Övervaka försök att låsa upp skärmen"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj för att inaktivera USB-felsökning."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Läget för testverktyg har aktiverats"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Inaktivera testverktygsläget genom att göra en återställning till standardinställningarna."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seriekonsolen är aktiverad"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Prestandan påverkas. Inaktivera via starthanteraren."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Vätska eller smuts i USB-porten"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-porten har inaktiverats automatiskt. Tryck för att läsa mer."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Nu kan du använda USB-porten"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Okategoriserad"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Du anger hur viktiga aviseringarna är."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Detta är viktigt på grund av personerna som deltar."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g> (det finns redan en användare med det här kontot)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Tillåter du att <xliff:g id="APP">%1$s</xliff:g> skapar en ny användare för <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Lägg till ett språk"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regionsinställningar"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Ange språket"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index c8c582f..565cdf9 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Inaruhusu programu kusoma na kuandika usanidi wa kipengee cha Usinisumbue."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"anzisha kipengele cha kuona matumizi ya ruhusa"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Huruhusu kishikiliaji kuanzisha matumizi ya ruhusa ya programu. Haipaswi kuhitajika kwa ajili ya programu za kawaida."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"kulenga njia ya mkato ya ufikivu"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Huruhusu programu kubainisha ulengaji wa njia ya mkato ya ufikivu."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Kuweka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Dhibiti urefu na maandishi yanayokubalika katika nenosiri la kufunga skrini na PIN."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Kuhesabu mara ambazo skrini inajaribu kufunguliwa"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chagua ili kulemaza utatuaji USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Hali ya Muunganisho wa Majaribio imewashwa"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Rejesha mipangilio iliyotoka nayo kiwandani ili uzime hali ya Muunganisho wa Majaribio."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Muunganisho kupitia mlango umewashwa"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Utendaji unaathirika. lli uzime, teua programu ya kuwasha mfumo wa uendeshaji."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Unyevu au uchafu katika mlango wa USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Mlango wa USB umezimwa kiotomatiki. Gusa ili upate maelezo zaidi."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Ni sawa kutumia mlango wa USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Ambazo aina haijabainishwa"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Uliweka mipangilio ya umuhimu wa arifa hizi."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Hii ni muhimu kwa sababu ya watu waliohusika."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Ruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g> (Je, tayari kuna mtumiaji anayetumia akaunti hii)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Ungependa kuruhusu <xliff:g id="APP">%1$s</xliff:g> iweke Mtumiaji mpya ikitumia <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Ongeza lugha"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Mapendeleo ya eneo"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Weka jina la lugha"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 0956aad..9d6d4e1 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -220,7 +220,7 @@
     <string name="reboot_safemode_title" msgid="7054509914500140361">"பாதுகாப்பான பயன்முறைக்கு மீண்டும் தொடங்கவும்"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"பாதுகாப்பான பயன்முறைக்குச் செல்ல மீண்டும் துவக்க விரும்புகிறீர்களா? நீங்கள் நிறுவிய எல்லா மூன்றாம் தரப்பு பயன்பாடுகளையும் இது முடக்கும். நீங்கள் மீண்டும் மறுதொடக்கம் செய்யும்போது அவை மீட்டமைக்கப்படும்."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"சமீபத்தியவை"</string>
-    <string name="no_recent_tasks" msgid="8794906658732193473">"சமீபத்திய பயன்பாடுகள் எதுவுமில்லை."</string>
+    <string name="no_recent_tasks" msgid="8794906658732193473">"சமீபத்திய ஆப்ஸ் எதுவுமில்லை."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"டேப்லெட் விருப்பங்கள்"</string>
     <string name="global_actions" product="tv" msgid="9091480417912345975">"Android TV விருப்பத்தேர்வுகள்"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"தொலைபேசி விருப்பங்கள்"</string>
@@ -271,7 +271,7 @@
     <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"ஆப்ஸ் இயங்குகிறது"</string>
     <string name="notification_channel_foreground_service" msgid="3931987440602669158">"பேட்டரியைப் பயன்படுத்தும் ஆப்ஸ்"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் பேட்டரியைப் பயன்படுத்துகிறது"</string>
-    <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> பயன்பாடுகள் பேட்டரியைப் பயன்படுத்துகின்றன"</string>
+    <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ஆப்ஸ் பேட்டரியைப் பயன்படுத்துகின்றன"</string>
     <string name="foreground_service_tap_for_details" msgid="372046743534354644">"பேட்டரி மற்றும் டேட்டா உபயோக விவரங்களைக் காண, தட்டவும்"</string>
     <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
@@ -345,11 +345,11 @@
     <string name="permlab_receiveMms" msgid="1821317344668257098">"உரைச் செய்திகளை (MMS) பெறுதல்"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"MMS செய்திகளைப் பெற, செயற்படுத்தப் ஆப்ஸை அனுமதிக்கிறது. இதற்கு அர்த்தம் உங்கள் சாதனத்திற்கு அனுப்பப்படும் செய்திகளை உங்களுக்குக் காட்டாமல் கண்காணிக்கவோ, நீக்கவோ ஆப்ஸால் முடியும் என்பதாகும்."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"செல் அலைபரப்புச் செய்திகளைப் படித்தல்"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"உங்கள் சாதனத்தில் பெறப்படும் செல் அலைபரப்புச் செய்திகளைப் படிப்பதற்குப் ஆப்ஸை அனுமதிக்கிறது. அவசரநிலை சூழ்நிலைகளை உங்களுக்கு எச்சரிக்கைச் செய்வதற்கு சில இடங்களில் செல் அலைபரப்பு விழிப்பூட்டல்கள் வழங்கப்படும். அவசரநிலை மொபைல் அலைபரப்புப் பெறப்படும்போது உங்கள் சாதனத்தின் செயல்திறன் அல்லது செயல்பாட்டுடன் தீங்கிழைக்கும் பயன்பாடுகள் அதைத் தடுக்கலாம்."</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"உங்கள் சாதனத்தில் பெறப்படும் செல் அலைபரப்புச் செய்திகளைப் படிப்பதற்குப் ஆப்ஸை அனுமதிக்கிறது. அவசரநிலை சூழ்நிலைகளை உங்களுக்கு எச்சரிக்கைச் செய்வதற்கு சில இடங்களில் செல் அலைபரப்பு விழிப்பூட்டல்கள் வழங்கப்படும். அவசரநிலை மொபைல் அலைபரப்புப் பெறப்படும்போது உங்கள் சாதனத்தின் செயல்திறன் அல்லது செயல்பாட்டுடன் தீங்கிழைக்கும் ஆப்ஸ் அதைத் தடுக்கலாம்."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"குழுசேர்ந்த ஊட்டங்களைப் படித்தல்"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"தற்போது ஒத்திசைந்த ஊட்டங்களைப் பற்றிய விவரங்களைப் பெற ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_sendSms" msgid="7544599214260982981">"SMS செய்திகளை அனுப்புதல் மற்றும் பார்த்தல்"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"SMS செய்திகளை அனுப்ப ஆப்ஸை அனுமதிக்கிறது. இதற்கு எதிர்பாராத பேமெண்ட்கள் விதிக்கப்படலாம். தீங்கு விளைவிக்கும் பயன்பாடுகள் உங்களின் உறுதிப்படுத்தல் எதுவுமின்றி செய்திகளை அனுப்பி உங்களுக்குக் கட்டணம் விதிக்கலாம்."</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"SMS செய்திகளை அனுப்ப ஆப்ஸை அனுமதிக்கிறது. இதற்கு எதிர்பாராத பேமெண்ட்கள் விதிக்கப்படலாம். தீங்கு விளைவிக்கும் ஆப்ஸ் உங்களின் உறுதிப்படுத்தல் எதுவுமின்றி செய்திகளை அனுப்பி உங்களுக்குக் கட்டணம் விதிக்கலாம்."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"உங்கள் உரைச் செய்திகளை (SMS அல்லது MMS) படித்தல்"</string>
     <string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"இந்த ஆப்ஸ் உங்கள் டேப்லெட்டில் சேமிக்கப்பட்டுள்ள எல்லா SMS (உரை) செய்திகளையும் படிக்கலாம்."</string>
     <string name="permdesc_readSms" product="tv" msgid="9106832390302749856">"உங்கள் Android TVயில் சேமித்துள்ள அனைத்து மெசேஜ்களையும் இந்த ஆப்ஸால் தெரிந்துகொள்ள முடியும்."</string>
@@ -357,7 +357,7 @@
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"உரைச் செய்திகளைப் (WAP) பெறுதல்"</string>
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAP செய்திகளைப் பெற, செயற்படுத்தப் ஆப்ஸை அனுமதிக்கிறது. உங்களுக்கு அனுப்பப்படும் செய்திகளை உங்களுக்குக் காட்டாமல் கண்காணிக்க அல்லது நீக்குவதற்கான திறன் இந்த அனுமதியில் உள்ளடங்கும்."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"இயங்கும் ஆப்ஸை மீட்டெடுத்தல்"</string>
-    <string name="permdesc_getTasks" msgid="7454215995847658102">"நடப்பில் மற்றும் சமீபத்தில் இயங்கும் காரியங்களின் தகவலைப் பெற ஆப்ஸை அனுமதிக்கிறது. சாதனத்தில் எந்தப் பயன்பாடுகள் பயன்படுத்தப்படுகின்றன என்பது குறித்த தகவலைக் கண்டறிய ஆப்ஸை இது அனுமதிக்கலாம்."</string>
+    <string name="permdesc_getTasks" msgid="7454215995847658102">"நடப்பில் மற்றும் சமீபத்தில் இயங்கும் காரியங்களின் தகவலைப் பெற ஆப்ஸை அனுமதிக்கிறது. சாதனத்தில் எந்த ஆப்ஸ் பயன்படுத்தப்படுகின்றன என்பது குறித்த தகவலைக் கண்டறிய ஆப்ஸை இது அனுமதிக்கலாம்."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"சுயவிவரத்தையும் சாதன உரிமையாளர்களையும் நிர்வகித்தல்"</string>
     <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"சுயவிவர உரிமையாளர்களையும் சாதன உரிமையாளரையும் அமைக்க, ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"இயங்கும் ஆப்ஸை மறுவரிசைப்படுத்தல்"</string>
@@ -365,9 +365,9 @@
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"கார் பயன்முறையை இயக்குதல்"</string>
     <string name="permdesc_enableCarMode" msgid="4853187425751419467">"கார் முறையை இயக்க, ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"பிற ஆப்ஸை மூடுதல்"</string>
-    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"பிற ஆப்ஸின் பின்புலச் செயல்முறைகளை நிறுத்த ஆப்ஸை அனுமதிக்கிறது. இதனால் பிற பயன்பாடுகள் இயங்குவதை நிறுத்தலாம்."</string>
+    <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"பிற ஆப்ஸின் பின்புலச் செயல்முறைகளை நிறுத்த ஆப்ஸை அனுமதிக்கிறது. இதனால் பிற ஆப்ஸ் இயங்குவதை நிறுத்தலாம்."</string>
     <string name="permlab_systemAlertWindow" msgid="7238805243128138690">"இந்த ஆப்ஸ் பிற ஆப்ஸின் மேலே தோன்றலாம்"</string>
-    <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்த ஆப்ஸ் பிற ஆப்ஸின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான ஆப்ஸ் உபயோகத்தில் குறுக்கிட்டு, பிற பயன்பாடுகள் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
+    <string name="permdesc_systemAlertWindow" msgid="2393776099672266188">"இந்த ஆப்ஸ் பிற ஆப்ஸின் மேலே அல்லது திரையின் பிற பகுதிகளில் தோன்றலாம். இது வழக்கமான ஆப்ஸ் உபயோகத்தில் குறுக்கிட்டு, பிற ஆப்ஸ் தோன்றும் விதத்தை மாற்றக்கூடும்."</string>
     <string name="permlab_runInBackground" msgid="7365290743781858803">"பின்னணியில் இயக்கு"</string>
     <string name="permdesc_runInBackground" msgid="7370142232209999824">"இந்த ஆப்ஸ், பின்னணியில் இயங்கலாம். இதனால் பேட்டரி விரைவாகத் தீர்ந்துவிடக்கூடும்."</string>
     <string name="permlab_useDataInBackground" msgid="8694951340794341809">"பின்னணியில் தரவைப் பயன்படுத்து"</string>
@@ -381,7 +381,7 @@
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"பயன்பாட்டுச் சேமிப்பு இடத்தை அளவிடல்"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"ஆப்ஸ், அதன் குறியீடு, தரவு, மற்றும் தற்காலிகச் சேமிப்பு அளவுகளை மீட்டெடுக்க அனுமதிக்கிறது"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"சாதன அமைப்புகளை மாற்றுதல்"</string>
-    <string name="permdesc_writeSettings" msgid="7775723441558907181">"முறைமையின் அமைப்பு தரவைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள், முறைமையின் உள்ளமைவைச் சிதைக்கலாம்."</string>
+    <string name="permdesc_writeSettings" msgid="7775723441558907181">"முறைமையின் அமைப்பு தரவைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் ஆப்ஸ், முறைமையின் உள்ளமைவைச் சிதைக்கலாம்."</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"தொடக்கத்தில் இயக்குதல்"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"மறுஇயக்கம் முடிந்தது, விரைவில் தானாகவே தொடங்க, ஆப்ஸை அனுமதிக்கிறது. இதனால் டேப்லெட் நீண்ட நேரம் கழித்து தொடங்கும் மற்றும் எப்போதும் இயங்குகின்ற டேப்லெட்டின் ஒட்டுமொத்தச் செயல்பாட்டையும் தாமதமாகும்."</string>
     <string name="permdesc_receiveBootCompleted" product="tv" msgid="6725487837446317527">"சாதனம் தொடங்கியவுடன் ஆப்ஸைத் தானாகவே தொடங்க அனுமதிக்கும். இது Android TV தொடங்குவதற்கான நேரத்தைத் தாமதமாக்குவதோடு எப்போதும் இயங்கிக்கொண்டிருப்பதன் மூலம் ஒட்டுமொத்த சாதனத்தின் வேகத்தைக் குறைக்கும்."</string>
@@ -391,9 +391,9 @@
     <string name="permdesc_broadcastSticky" product="tv" msgid="5029460344724532288">"வலைபரப்பு முடிந்த பின்னரும் தங்கிவிடும் ஸ்டிக்கி வலைபரப்புகளை அனுப்ப ஆப்ஸை அனுமதிக்கும். அளவுக்கதிகமான உபயோகம் Android TVயின் வேகத்தைக் குறைக்கவோ நிலையற்றதாகவோ ஆக்கக்கூடும். இதனால் அதிகமான நினைவகம் பயன்படுத்தப்படும்."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"அலைபரப்பு முடிந்த பின்னும் இருக்கும், தொடர்ந்து அணுகத்தக்க அலைபரப்பை அனுப்பப் ஆப்ஸை அனுமதிக்கிறது. அதிகமாகப் பயன்படுத்தினால், மொபைலானது நினைவகத்தை மிக அதிகமாகப் பயன்படுத்துவதால் வேகம் குறைந்ததாகவும், நிலையற்றதாகவும் ஆகலாம்."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"உங்கள் தொடர்புகளைப் படித்தல்"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"குறிப்பிட்டவர்களுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்டதின் எண்ணிக்கை உட்பட, உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. இந்த அனுமதி, உங்கள் தொடர்பு தரவைச் சேமிக்க ஆப்ஸை அனுமதிக்கிறது, மேலும் தீங்கிழைக்கும் பயன்பாடுகள் உங்களுக்குத் தெரியாமல் தொடர்பு தரவைப் பகிரலாம்."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"குறிப்பிட்டவர்களுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்டதின் எண்ணிக்கை உட்பட, உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. இந்த அனுமதி, உங்கள் தொடர்பு தரவைச் சேமிக்க ஆப்ஸை அனுமதிக்கிறது, மேலும் தீங்கிழைக்கும் ஆப்ஸ் உங்களுக்குத் தெரியாமல் தொடர்பு தரவைப் பகிரலாம்."</string>
     <string name="permdesc_readContacts" product="tv" msgid="3890061004911027912">"உங்கள் Android TVயில் சேமித்துள்ள தொடர்புகள் பற்றிய தரவைத் தெரிந்துகொள்ள ஆப்ஸை அனுமதிக்கும். குறிப்பிட்ட தனிநபரை எத்தனை முறை அழைத்தீர்கள், பிறவழிகளில் தொடர்புகொண்டீர்கள் அல்லது அவருக்கு எத்தனை முறை மின்னஞ்சல் அனுப்பினீர்கள் என்பதும் இதில் அடங்கும். இது உங்கள் தொடர்புத் தரவைச் சேமிக்க ஆப்ஸை அனுமதிக்கும், அத்துடன் தீங்குவிளைவிக்கும் ஆப்ஸ் உங்களுக்குத் தெரியாமல் தொடர்புத் தரவைப் பகிரக்கூடும்."</string>
-    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"குறிப்பிட்டவர்களுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்ட எண்ணிக்கை உட்பட, உங்கள் மொபைலில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. இந்த அனுமதி, உங்கள் தொடர்பு தரவைச் சேமிக்க ஆப்ஸை அனுமதிக்கிறது, மேலும் தீங்கிழைக்கும் பயன்பாடுகள் உங்களுக்குத் தெரியாமல் தொடர்பு தரவைப் பகிரலாம்."</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"குறிப்பிட்டவர்களுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்ட எண்ணிக்கை உட்பட, உங்கள் மொபைலில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. இந்த அனுமதி, உங்கள் தொடர்பு தரவைச் சேமிக்க ஆப்ஸை அனுமதிக்கிறது, மேலும் தீங்கிழைக்கும் ஆப்ஸ் உங்களுக்குத் தெரியாமல் தொடர்பு தரவைப் பகிரலாம்."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"உங்கள் தொடர்புகளை மாற்றுதல்"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"குறிப்பிட்ட தொடர்புகளுடன் நீங்கள் அழைத்த, மின்னஞ்சல் அனுப்பிய அல்லது வேறு வழியில் தொடர்புகொண்டதின் எண்ணிக்கை உள்பட, உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உங்கள் தொடர்புகள் குறித்த தரவைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இந்த அனுமதியானது தொடர்புத் தரவை நீக்க ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="307929337692573341">"உங்கள் Android TVயில் சேமித்துள்ள தொடர்புகள் பற்றிய தரவை மாற்ற ஆப்ஸை அனுமதிக்கும். குறிப்பிட்ட தொடர்பை எத்தனை முறை அழைத்தீர்கள், பிறவழிகளில் தொடர்புகொண்டீர்கள் அல்லது அவருக்கு எத்தனை முறை மின்னஞ்சல் அனுப்பினீர்கள் என்பதும் இதில் அடங்கும். தொடர்புத் தரவை நீக்க ஆப்ஸை இது அனுமதிக்கும்."</string>
@@ -401,9 +401,9 @@
     <string name="permlab_readCallLog" msgid="3478133184624102739">"அழைப்புப் பதிவைப் படித்தல்"</string>
     <string name="permdesc_readCallLog" msgid="3204122446463552146">"இந்த ஆப்ஸ் உங்கள் அழைப்பு வரலாற்றைப் படிக்கலாம்."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"அழைப்புப் பதிவை எழுதுதல்"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்பட உங்கள் டேப்லெட்டின் அழைப்புப் பதிவைத் திருத்துவதற்குப் ஆப்ஸை அனுமதிக்கிறது. உங்கள் அழைப்பின் பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்பட உங்கள் டேப்லெட்டின் அழைப்புப் பதிவைத் திருத்துவதற்குப் ஆப்ஸை அனுமதிக்கிறது. உங்கள் அழைப்பின் பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="7939219462637746280">"உள்வரும், வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உட்பட உங்கள் Android TVயின் அழைப்புப் பதிவைத் திருத்த ஆப்ஸை அனுமதிக்கும். உங்கள் அழைப்புப் பதிவை அழிக்கவோ திருத்தவோ தீங்கு விளைவிக்கும் ஆப்ஸ் இதைப் பயன்படுத்தக்கூடும்."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்பட உங்கள் மொபைல் அழைப்புப் பதிவைத் திருத்துவதற்குப் ஆப்ஸை அனுமதிக்கிறது. உங்கள் அழைப்பின் பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"உள்வரும் மற்றும் வெளிச்செல்லும் அழைப்புகள் குறித்த தகவல் உள்பட உங்கள் மொபைல் அழைப்புப் பதிவைத் திருத்துவதற்குப் ஆப்ஸை அனுமதிக்கிறது. உங்கள் அழைப்பின் பதிவை அழிக்க அல்லது திருத்த தீங்கு விளைவிக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"உடல் உணர்விகளை (இதயத் துடிப்பு மானிட்டர்கள் போன்றவை) அணுகுதல்"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"உங்கள் இதயத்துடிப்பு விகிதம் போன்ற உங்கள் உடல்நிலையைக் கண்காணிக்கும் உணர்விகளில் இருந்து தரவை அணுக ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="permlab_readCalendar" msgid="6716116972752441641">"கேலெண்டர் நிகழ்வுகளையும் விவரங்களையும் படிக்கலாம்"</string>
@@ -439,7 +439,7 @@
     <string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
-    <string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் ஆப்ஸை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது ஆப்ஸை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் ஆப்ஸை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது ஆப்ஸை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் ஆப்ஸ், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"உங்கள் குறுக்கீடின்றி IMS சேவையைப் பயன்படுத்தி அழைப்பதற்கு, ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"மொபைல் நிலை மற்றும் அடையாளத்தைப் படித்தல்"</string>
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"தொந்தரவு செய்ய வேண்டாம் உள்ளமைவைப் படிக்கவும் எழுதவும், ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"அனுமதி உபயோகத்தை அணுகுதல்"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"ஆப்ஸிற்கான அனுமதி உபயோகத்தை ஹோல்டருக்கு வழங்கும். இயல்பான ஆப்ஸிற்கு இது எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"அணுகலம்ச ஷார்ட்கட் இலக்கு"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"அணுகலம்ச ஷார்ட்கட் இலக்கை விளக்க ஆப்ஸை அனுமதிக்கும்."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"கடவுச்சொல் விதிகளை அமைக்கவும்"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"திரைப் பூட்டின் கடவுச்சொற்கள் மற்றும் பின்களில் அனுமதிக்கப்படும் நீளத்தையும் எழுத்துக்குறிகளையும் கட்டுப்படுத்தும்."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"திரையைத் திறப்பதற்கான முயற்சிகளைக் கண்காணி"</string>
@@ -939,15 +941,15 @@
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"உங்கள் இணையப் புத்தக்கக்குறிகள் மற்றும் வரலாற்றைப் படித்தல்"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"உலாவி மூலம் பார்வையிட்ட எல்லா URLகளின் வரலாற்றையும், உலாவியில் குறிக்கப்பட்ட எல்லா புத்தகக்குறிகளையும் படிக்கப் ஆப்ஸை அனுமதிக்கிறது. குறிப்பு: மூன்றாம் தரப்பு உலாவிகள் அல்லது இணைய உலாவல் திறன்களுடன் கூடிய பிற பயன்பாடுகளால் இந்த அனுமதி செயற்படுத்தப்படாமல் போகலாம்."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"இணையப் புத்தகக்குறிகளையும், வரலாற்றையும் எழுதுதல்"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உலாவியின் வரலாறு அல்லது புத்தகக்குறிகளைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இது உலாவியின் தரவை அழிக்கவோ, திருத்தவோ ஆப்ஸை அனுமதிக்கலாம். குறிப்பு: இணைய உலாவல் செயல்திறன்கள் மூலம் மூன்றாம் தரப்பு உலாவிகள் அல்லது பிற பயன்பாடுகள் இந்த அனுமதியைச் செயற்படுத்த முடியாது."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உலாவியின் வரலாறு அல்லது புத்தகக்குறிகளைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இது உலாவியின் தரவை அழிக்கவோ, திருத்தவோ ஆப்ஸை அனுமதிக்கலாம். குறிப்பு: இணைய உலாவல் செயல்திறன்கள் மூலம் மூன்றாம் தரப்பு உலாவிகள் அல்லது பிற ஆப்ஸ் இந்த அனுமதியைச் செயற்படுத்த முடியாது."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="6340829212433680418">"Android TVயில் சேமித்துள்ள உலாவியின் மூலம் பார்க்கப்பட்ட தளங்களையோ புக்மார்க்குகளையோ திருத்த ஆப்ஸை அனுமதிக்கும். இது உலாவியின் தரவை அழிக்கவோ திருத்தவோ ஆப்ஸை அனுமதிக்கக்கூடும். கவனத்திற்கு: மூன்றாம் தரப்பு உலாவிகளோ இணைய உலாவல் திறன்களுடன் கூடிய பிற ஆப்ஸோ இந்த அனுமதியைச் செயல்படுத்த முடியாது."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"உங்கள் மொபைலில் சேமிக்கப்பட்ட உலாவியின் வரலாறு அல்லது புத்தகக்குறிகளைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இது உலாவியின் தரவை அழிக்கவோ, திருத்தவோ ஆப்ஸை அனுமதிக்கலாம். குறிப்பு: இணைய உலாவல் செயல்திறன்கள் மூலம் மூன்றாம் தரப்பு உலாவிகள் அல்லது பிற பயன்பாடுகள் இந்த அனுமதியைச் செயற்படுத்த முடியாது."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"உங்கள் மொபைலில் சேமிக்கப்பட்ட உலாவியின் வரலாறு அல்லது புத்தகக்குறிகளைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இது உலாவியின் தரவை அழிக்கவோ, திருத்தவோ ஆப்ஸை அனுமதிக்கலாம். குறிப்பு: இணைய உலாவல் செயல்திறன்கள் மூலம் மூன்றாம் தரப்பு உலாவிகள் அல்லது பிற ஆப்ஸ் இந்த அனுமதியைச் செயற்படுத்த முடியாது."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"அலாரத்தை அமைத்தல்"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"நிறுவிய அலார கடிகாரப் பயன்பாட்டில் அலாரத்தை அமைக்க, ஆப்ஸை அனுமதிக்கிறது. சில அலார கடிகார பயன்பாடுகளில் இந்த அம்சம் இல்லாமல் இருக்கலாம்."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"குரலஞ்சலைச் சேர்த்தல்"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"குரலஞ்சல் இன்பாக்ஸில் செய்திகளைச் சேர்க்க, ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"உலாவியின் புவியியல் இருப்பிடம் சார்ந்த அனுமதிகளைத் திருத்துதல்"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"உலாவியின் புவியியல் இருப்பிடம் சார்ந்த அனுமதிகளைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. இடத் தகவலை தன்னிச்சையான இணையதளங்களுக்கு அனுப்புவதை அனுமதிக்க, தீங்குவிளைவிக்கும் பயன்பாடுகள் இதைப் பயன்படுத்தலாம்."</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"உலாவியின் புவியியல் இருப்பிடம் சார்ந்த அனுமதிகளைத் திருத்த, ஆப்ஸை அனுமதிக்கிறது. இடத் தகவலை தன்னிச்சையான இணையதளங்களுக்கு அனுப்புவதை அனுமதிக்க, தீங்குவிளைவிக்கும் ஆப்ஸ் இதைப் பயன்படுத்தலாம்."</string>
     <string name="save_password_message" msgid="767344687139195790">"இந்தக் கடவுச்சொல்லை உலாவி நினைவில்கொள்ள விரும்புகிறீர்களா?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"இப்போது இல்லை"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"நினைவில்கொள்"</string>
@@ -1156,10 +1158,10 @@
     <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"படமெடு"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"இந்தச் செயலுக்கு இயல்பாகப் பயன்படுத்து."</string>
     <string name="use_a_different_app" msgid="8134926230585710243">"வேறு ஆப்ஸைப் பயன்படுத்தவும்"</string>
-    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"முறைமை அமைப்பு &gt; பயன்பாடுகள் &gt; பதிவிறக்கியவை என்பதில் உள்ள இயல்பை அழிக்கவும்."</string>
+    <string name="clearDefaultHintMsg" msgid="3252584689512077257">"முறைமை அமைப்பு &gt; ஆப்ஸ் &gt; பதிவிறக்கியவை என்பதில் உள்ள இயல்பை அழிக்கவும்."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"செயலைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"USB சாதனத்திற்கான பயன்பாட்டைத் தேர்வுசெய்க"</string>
-    <string name="noApplications" msgid="2991814273936504689">"இந்தச் செயலைச் செய்ய பயன்பாடுகள் எதுவுமில்லை."</string>
+    <string name="noApplications" msgid="2991814273936504689">"இந்தச் செயலைச் செய்ய ஆப்ஸ் எதுவுமில்லை."</string>
     <string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> செயலிழந்தது"</string>
     <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> செயலிழந்தது"</string>
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> தொடர்ந்து செயலிழக்கிறது"</string>
@@ -1184,7 +1186,7 @@
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> உண்மையாக வெளியிடப்பட்டது."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"அளவு"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"எப்போதும் காட்டு"</string>
-    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு &gt; பயன்பாடுகள் &gt; பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"சிஸ்டம் அமைப்பு &gt; ஆப்ஸ் &gt; பதிவிறக்கம் என்பதில் இதை மீண்டும் இயக்கவும்."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"தற்போதைய திரை அளவு அமைப்பை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காததால், அது வழக்கத்திற்கு மாறாகச் செயல்படக்கூடும்."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"எப்போதும் காட்டு"</string>
     <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடானது, இந்தச் சாதனத்தின் Android OSக்கு இணக்கமற்ற பதிப்பிற்காக உருவாக்கப்பட்டதால், இதில் சரியாகச் செயல்படாது. இந்த ஆப்ஸின் புதுப்பிக்கப்பட்ட பதிப்பானது தற்போது கிடைக்கக்கூடும்."</string>
@@ -1204,7 +1206,7 @@
     <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g>ஐ மேம்படுத்துகிறது…"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> ஆப்ஸை ஒருங்கிணைக்கிறது."</string>
     <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g>ஐத் தயார்செய்கிறது."</string>
-    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"பயன்பாடுகள் தொடங்கப்படுகின்றன."</string>
+    <string name="android_upgrading_starting_apps" msgid="451464516346926713">"ஆப்ஸ் தொடங்கப்படுகின்றன."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"துவக்குதலை முடிக்கிறது."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> இயங்குகிறது"</string>
     <string name="heavy_weight_notification_detail" msgid="2304833848484424985">"கேமிற்குச் செல்ல, தட்டவும்"</string>
@@ -1322,7 +1324,7 @@
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"அனுப்பு"</string>
     <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ரத்துசெய்"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"எனது விருப்பத்தேர்வை நினைவில்கொள்"</string>
-    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"அமைப்பு &gt; பயன்பாடுகள் என்பதில் பிறகு நீங்கள் மாற்றலாம்"</string>
+    <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"அமைப்பு &gt; ஆப்ஸ் என்பதில் பிறகு நீங்கள் மாற்றலாம்"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"எப்போதும் அனுமதி"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"ஒருபோதும் அனுமதிக்காதே"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"சிம் கார்டு அகற்றப்பட்டது"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB பிழைதிருத்தத்தை முடக்க, தேர்ந்தெடுக்கவும்."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"\'தன்னியக்க சோதனைப்\' பயன்முறை இயக்கப்பட்டது"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"’தன்னியக்க சோதனைப்\' பயன்முறையை முடக்க ஆரம்பநிலைக்கு மீட்டமைக்கவும்."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"சீரியல் கன்சோல் இயக்கப்பட்டது"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"செயல்திறன் பாதிக்கப்பட்டுள்ளது. முடக்குவதற்கு பூட்லோடரைத் தேர்வுசெய்யவும்."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB போர்ட்டில் சேதம் உள்ளது"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB போர்ட் தானாகவே முடக்கப்பட்டது மேலும் அறிய, தட்டவும்."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB போர்ட்டைப் பயன்படுத்தலாம்"</string>
@@ -1446,7 +1450,7 @@
     <string name="ime_action_default" msgid="2840921885558045721">"செயலாக்கு"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g> ஐப் பயன்படுத்தி\nஅழை"</string>
     <string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g> ஐப்\nபயன்படுத்தி தொடர்பை உருவாக்கு"</string>
-    <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"பின்வரும் ஒன்று அல்லது அதற்கு மேற்பட்ட பயன்பாடுகள், இப்போதும் எதிர்காலத்திலும் உங்கள் கணக்கை அணுகுவதற்கான அனுமதியைக் கோருகின்றன."</string>
+    <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"பின்வரும் ஒன்று அல்லது அதற்கு மேற்பட்ட ஆப்ஸ், இப்போதும் எதிர்காலத்திலும் உங்கள் கணக்கை அணுகுவதற்கான அனுமதியைக் கோருகின்றன."</string>
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"இந்தக் கோரிக்கையை அனுமதிக்க விரும்புகிறீர்களா?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"‍அணுகல் கோரிக்கை"</string>
     <string name="allow" msgid="7225948811296386551">"அனுமதி"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"வகைப்படுத்தப்படாதவை"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"இந்த அறிவிப்புகளின் முக்கியத்துவத்தை அமைத்துள்ளீர்கள்."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ஈடுபட்டுள்ளவர்களின் காரணமாக, இது முக்கியமானது."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா (இந்தக் கணக்கில் ஏற்கெனவே ஒரு பயனர் உள்ளார்) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> மூலம் புதிய பயனரை உருவாக்க <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸை அனுமதிக்கவா?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"மொழியைச் சேர்"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"மண்டல விருப்பம்"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"மொழி பெயரை உள்ளிடுக"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index a8550f8..a14bcb9 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"యాప్‌నకు అనుమతి వినియోగాన్ని ప్రారంభించడానికి హోల్డర్‌‌ను అనుమతిస్తుంది. సాధారణ యాప్‌లకు ఎప్పటికీ ఇటువంటి అనుమతి అవసరం ఉండదు."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"యాక్సెసిబిలిటీ షార్ట్‌కట్ లక్ష్యం"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"యాక్సెసిబిలిటీ షార్ట్‌కట్ లక్ష్యాన్ని నిర్వచించడానికి యాప్‌ను అనుమతించండి."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"పాస్‌వర్డ్ నియమాలను సెట్ చేయండి"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"స్క్రీన్ లాక్ పాస్‌వర్డ్‌లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"స్క్రీన్ అన్‌లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string>
@@ -1330,7 +1332,7 @@
     <string name="sim_done_button" msgid="827949989369963775">"పూర్తయింది"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"సిమ్ కార్డు జోడించబడింది"</string>
     <string name="sim_added_message" msgid="6599945301141050216">"మొబైల్ నెట్‌వర్క్‌ను యాక్సెస్ చేయడానికి మీ పరికరాన్ని పునఃప్రారంభించండి."</string>
-    <string name="sim_restart_button" msgid="4722407842815232347">"పునఃప్రారంభించు"</string>
+    <string name="sim_restart_button" msgid="4722407842815232347">"రీస్టార్ట్ చేయి"</string>
     <string name="install_carrier_app_notification_title" msgid="9056007111024059888">"మొబైల్ సేవను సక్రియం చేయండి"</string>
     <string name="install_carrier_app_notification_text" msgid="3346681446158696001">"మీ కొత్త SIMని సక్రియం చేయడానికి క్యారియర్ యాప్‌ను డౌన్‌లోడ్ చేయండి"</string>
     <string name="install_carrier_app_notification_text_app_name" msgid="1196505084835248137">"మీ కొత్త SIMని సక్రియం చేయడం కోసం <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్‌ని డౌన్‌లోడ్ చేయండి"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"డీబగ్గింగ్‌ని నిలిపివేయడానికి ఎంచుకోండి."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"పరీక్ష నియంత్రణ మోడ్ ప్రారంభించబడింది"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"పరీక్ష నియంత్రణ మోడ్‌ను నిలిపివేయడానికి ఫ్యాక్టరీ రీసెట్‍‌ను అమలు చేయండి."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"సీరియల్ కన్సోల్ ప్రారంభించబడింది"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"పని తీరు ప్రభావితమైంది. నిలిపివేయడానికి, బూట్‌లోడర్‌ను తనిఖీ చేయండి."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB పోర్ట్‌లో ద్రవ లేదా వ్యర్థ పదార్థాలు ఉన్నాయి"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB పోర్ట్ ఆటోమేటిక్‌గా నిలిపివేయబడింది. మరింత తెలుసుకోవడానికి నొక్కండి."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB పోర్ట్‌ను ఉపయోగించడం సురక్షితం"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"వర్గీకరించబడలేదు"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"మీరు ఈ నోటిఫికేషన్‌ల ప్రాముఖ్యతను సెట్ చేసారు."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ఇందులో పేర్కొనబడిన వ్యక్తులను బట్టి ఇది చాలా ముఖ్యమైనది."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా (ఈ ఖాతాతో ఇప్పటికే ఒక వినియోగదారు ఉన్నారు) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g>తో కొత్త వినియోగదారుని సృష్టించడానికి <xliff:g id="APP">%1$s</xliff:g>ను అనుమతించాలా?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"భాషను జోడించండి"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ప్రాంతం ప్రాధాన్యత"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"భాష పేరును టైప్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index f2376d7..4210354 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"อนุญาตให้แอปอ่านและเขียนการกำหนดค่าโหมดห้ามรบกวน"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"เริ่มการใช้สิทธิ์การดู"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"อนุญาตให้เจ้าของเริ่มการใช้สิทธิ์ของแอป ไม่จำเป็นสำหรับแอปทั่วไป"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"เป้าหมายทางลัดการช่วยเหลือพิเศษ"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"อนุญาตให้แอปกำหนดเป้าหมายทางลัดการช่วยเหลือพิเศษ"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ควบคุมความยาวและอักขระที่สามารถใช้ในรหัสผ่านของการล็อกหน้าจอและ PIN"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"โหมดโปรแกรมทดสอบอัตโนมัติเปิดใช้อยู่"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อปิดใช้โหมดโปรแกรมทดสอบอัตโนมัติ"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"เปิดใช้คอนโซลการเรียงอันดับแล้ว"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"ประสิทธิภาพได้รับผลกระทบ ตรวจสอบ Bootloader เพื่อปิดใช้งาน"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"มีของเหลวหรือฝุ่นละอองในพอร์ต USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"พอร์ต USB ปิดใช้โดยอัตโนมัติ แตะเพื่อดูข้อมูลเพิ่มเติม"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"ใช้พอร์ต USB ได้แล้ว"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"ไม่จัดอยู่ในหมวดหมู่ใดๆ"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"คุณตั้งค่าความสำคัญของการแจ้งเตือนเหล่านี้"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"ข้อความนี้สำคัญเนื่องจากบุคคลที่เกี่ยวข้อง"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม (มีผู้ใช้ที่มีบัญชีนี้อยู่แล้ว)"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"อนุญาตให้ <xliff:g id="APP">%1$s</xliff:g> สร้างผู้ใช้ใหม่ด้วย <xliff:g id="ACCOUNT">%2$s</xliff:g> ไหม"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"เพิ่มภาษา"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"ค่ากำหนดภูมิภาค"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"พิมพ์ชื่อภาษา"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 9acd72a..70d2a2f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Nagbibigay-daan sa app na basahin at isulat ang configuration ng Huwag Istorbohin."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"simulan ang paggamit sa pahintulot sa pagtingin"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Binibigyang-daan ang may hawak na simulan ang paggamit ng pahintulot para sa isang app. Hindi dapat kailanganin kailanman para sa mga normal na app."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"Target ng shortcut sa pagiging accessible"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Nagbibigay-daan sa isang app na tukuyin ang target ng shortcut sa pagiging accessible."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolin ang haba at ang mga character na pinapayagan sa mga password at PIN sa screen lock."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Piliin upang i-disable ang debugging ng USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Naka-enable ang Test Harness Mode"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Mag-factory reset para i-disable ang Test Harness Mode."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Naka-enable ang serial console"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Naaapektuhan ang performance. Para i-disable, lagyan ng check ang bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Liquid o debris sa USB port"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Awtomatikong na-disable ang USB port. Mag-tap para matuto pa."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Ayos na gamitin ang USB port"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Di-nakategorya"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ikaw ang magtatakda sa kahalagahan ng mga notification na ito."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Mahalaga ito dahil sa mga taong kasangkot."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> (mayroon nang User sa account na ito) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Payagan ang <xliff:g id="APP">%1$s</xliff:g> na gumawa ng bagong User sa <xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Magdagdag ng wika"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Kagustuhan sa rehiyon"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"I-type ang wika"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e2bda9f..94e21dc 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Uygulamaya, Rahatsız Etmeyin yapılandırmasını okuma ve yazma izni verir."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"izin kullanımı görüntülemeye başlama"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"İzin sahibinin bir uygulama için izin kullanımı başlatmasına olanak tanır. Normal uygulamalar için hiçbir zaman kullanılmamalıdır."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"erişilebilirlik kısayolu hedefi"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Uygulamaların erişilebilirlik kısayolu hedefi tanımlamasına izin verir."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran kilidini açma şifrelerinde ve PIN\'lerde izin verilen uzunluğu ve karakterleri denetleyin."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Ekran kilidini açma denemelerini izle"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için seçin."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Test Bandı Modu etkin"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Test Bandı Modu\'nu devre dışı bırakmak için cihazı fabrika ayarlarına sıfırlayın."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Seri konsol etkinleştirildi"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Performans etkilendi. Devre dışı bırakmak için bootloader\'ı kontrol edin."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB bağlantı noktasında sıvı veya toz var"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB bağlantı noktası otomatik olarak devre dışı bırakıldı. Daha fazla bilgi için dokunun."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB bağlantı noktasını kullanabilirsiniz"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Kategorize edilmemiş"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bu bildirimlerin önem derecesini ayarladınız."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu, dahil olan kişiler nedeniyle önemlidir."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi (bu hesaba sahip bir kullanıcı zaten var)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> uygulamasının <xliff:g id="ACCOUNT">%2$s</xliff:g> hesabına sahip yeni bir Kullanıcı eklemesine izin verilsin mi?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Dil ekleyin"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Bölge tercihi"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Dil adını yazın"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index ee52575..3c30609 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -661,6 +661,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Додаток зможе переглядати та змінювати конфігурацію режиму \"Не турбувати\"."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"перегляньте дані про використання дозволів"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Власник зможе використовувати дозволи для цього додатка. Цей дозвіл не потрібен для звичайних додатків."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"потрібні засоби спеціальних можливостей"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Дає додатку змогу визначати потрібні засоби спеціальних можливостей."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Укажіть максимальну довжину та кількість символів для паролів розблокування екрана та PIN-кодів."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Відстежувати спроби розблокування екрана"</string>
@@ -1405,6 +1407,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Виберіть, щоб вимкнути налагодження за USB"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Увімкнено режим автоматизованого тестування"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Щоб вимкнути режим автоматизованого тестування, відновіть заводські налаштування."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Послідовну консоль увімкнено"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Продуктивність зазнала впливу. Щоб вимкнути, перевірте завантажувач операційної системи."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Рідина або сміття в USB-порту"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB-порт автоматично вимкнено. Торкніться, щоб дізнатися більше."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Можна використовувати USB-порт"</string>
@@ -1958,10 +1962,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Без категорії"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Ви вказуєте пріоритет цих сповіщень."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Важливе з огляду на учасників."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g> (користувач із таким обліковим записом уже існує)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Дозволити додатку <xliff:g id="APP">%1$s</xliff:g> створити нового користувача з обліковим записом <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Додати мову"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Вибір регіону"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Введіть назву мови"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5cc8db7..59b30f0 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"ایپ کو ڈسٹرب نہ کریں کنفیگریشن لکھنے اور پڑھنے کے قابل کرتا ہے۔"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"اجازت کی استعمال کا ملاحظہ شروع کریں"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"حامل کو ایپ کی اجازت کے استعمال کو شروع کرنے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی درکار نہیں ہونا چاہیے۔"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"ایکسیسبیلٹی شارٹ کٹ ہدف"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"ایپ کو ایکسیسبیلٹی شارٹ کٹ ہدف کی وضاحت کرنے کے ليے اجازتیں۔"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"پاس ورڈ کے اصول سیٹ کریں"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"‏اسکرین لاک پاس ورڈز اور PINs میں اجازت یافتہ لمبائی اور حروف کو کنٹرول کریں۔"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"اسکرین غیر مقفل کرنے کی کوششیں مانیٹر کریں"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏USB ڈیبگ کرنے کو غیر فعال کرنے کیلئے منتخب کریں۔"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"ٹیسٹ ہارنیس موڈ فعال ہے"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"ٹیسٹ ہارنیس موڈ غیر فعال کرنے کے لیے فیکٹری ری سیٹ کریں۔"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"شمار کونسول فعال ہے"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"کارکردگی پر اثر پڑا ہے۔ غیر فعال کرنے کے ليے، بوٹ لوڈر چیک کریں۔"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"‏USB پورٹ میں سیال یا دھول ہے"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"‏USB پورٹ خودکار طور پر غیر فعال کر دیا گیا۔ مزید جاننے کیلئے تھپتھپائیں۔"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"‏USB پورٹ کا استعمال ٹھیک ہے"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"غیر زمرہ بند"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"ان اطلاعات کی اہمیت آپ مقرر کرتے ہیں۔"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"اس میں موجود لوگوں کی وجہ سے یہ اہم ہے۔"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> کو <xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ ایک نیا صارف بنانے کی اجازت دیں (اس اکاؤنٹ کے ساتھ ایک صارف پہلے سے موجود ہے) ؟"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="ACCOUNT">%2$s</xliff:g> کے ساتھ نئے صارف کو تخلیق کرنے کے لیے <xliff:g id="APP">%1$s</xliff:g> کو اجازت دیں ؟"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"ایک زبان شامل کریں"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"علاقہ کی ترجیح"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"زبان کا نام ٹائپ کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index cb5191d..22655d0 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"“Bezovta qilinmasin” rejimi sozlamalarini ko‘rish va o‘zgartirish."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"foydalaniladigan ruxsatlar axborotini ochish"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Ilova foydalanadigan ruxsatlar axborotini ishga tushirishga ruxsat beradi. Oddiy ilovalar uchun talab qilinmaydi."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"tezkor yoqish maqsadi"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Ilova tezkor yoqish maqsadini aniqlay oladi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qoidalarini o‘rnatish"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran qulfi paroli va PIN kodlari uchun qo‘yiladigan talablarni (belgilar soni va uzunligi) nazorat qiladi."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Ekranni qulfdan chiqarishga urinishlarni nazorat qilish"</string>
@@ -1362,6 +1364,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Xavfsizlik sinovi rejimi yoqildi"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Xavfsizlik sinovi rejimini faolsizlantirish uchun zavod sozlamalariga qaytaring."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Davomiy port terminali yoqildi"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Samaradorlik pasaydi. Terminalni faolsizlantirish uchun operatsion tizim yuklagichini oching."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB portda suyuqlik yoki parcha bor"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB port avtomatik tarzda faolsizlashtirildi. Batafsil axborot olish uchun bosing."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB portdan foydalanish mumkin"</string>
@@ -1891,10 +1895,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Turkumlanmagan"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Siz ushbu bildirishnomalarning muhimligini belgilagansiz."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Bu odamlar siz uchun muhim."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi (bunday hisobdagi foydalanuvchi allaqachon mavjud) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"<xliff:g id="APP">%1$s</xliff:g> ilovasiga <xliff:g id="ACCOUNT">%2$s</xliff:g> hisobi bilan yangi foydalanuvchi yaratishiga ruxsat berilsinmi ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Til qoʻshish"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Hudud sozlamalari"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Til nomini kiriting"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e41dc43..f36d993 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Cho phép ứng dụng đọc và ghi cấu hình Không làm phiền."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"cấp quyền xem"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Cho phép chủ sở hữu cấp quyền cho một ứng dụng. Các ứng dụng thông thường sẽ không bao giờ cần quyền này."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"đích đến của phím tắt hỗ trợ tiếp cận"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Cho phép ứng dụng xác định đích đến của phím tắt hỗ trợ tiếp cận."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kiểm soát độ dài và ký tự được phép trong mật khẩu khóa màn hình và mã PIN."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chọn để tắt chế độ gỡ lỗi qua USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Đã bật Chế độ khai thác kiểm thử"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Khôi phục cài đặt gốc để tắt Chế độ khai thác kiểm thử."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"Đã bật bảng điều khiển cổng nối tiếp"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Hiệu suất sẽ bị ảnh hưởng. Để tắt, hãy chọn trình tải khởi động."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Có chất lỏng hoặc mảnh vỡ trong cổng USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Cổng USB đã tự động tắt. Nhấn để tìm hiểu thêm."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"Có thể sử dụng cổng USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Chưa được phân loại"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Bạn đặt tầm quan trọng của các thông báo này."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Thông báo này quan trọng vì những người có liên quan."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g> (đã tồn tại người dùng có tài khoản này)?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Cho phép <xliff:g id="APP">%1$s</xliff:g> tạo người dùng mới bằng <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Thêm ngôn ngữ"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Tùy chọn khu vực"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Nhập tên ngôn ngữ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index ba39f1e2..461bbb0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"允许此应用读取和写入“勿扰”模式配置。"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"授权使用“查看权限”"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"允许该应用开始查看应用的权限使用情况(普通应用绝不需要此权限)。"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"无障碍功能快捷方式目标"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"允许应用定义无障碍功能快捷方式目标。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制锁屏密码和 PIN 码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"监控屏幕解锁尝试次数"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"选择即可停用 USB 调试功能。"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"自动化测试框架模式已启用"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"恢复出厂设置以停用自动化测试框架模式。"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"已启用序列控制台"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"性能受到影响。要停用,请查看引导加载程序。"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB 端口中有液体或碎屑"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB 端口已自动停用。点按即可了解详情。"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"允许使用 USB 端口"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"未分类"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"这些通知的重要程度由您来设置。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"这条通知涉及特定的人,因此被归为重要通知。"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g>(目前已有用户使用此帐号)创建新用户吗?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"允许<xliff:g id="APP">%1$s</xliff:g>使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 创建新用户吗?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"添加语言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"区域偏好设置"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"输入语言名称"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index f0fce71..a57b4eb 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -201,7 +201,7 @@
     <string name="turn_on_radio" msgid="3912793092339962371">"開啟無線網絡"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"關閉無線網絡"</string>
     <string name="screen_lock" msgid="799094655496098153">"螢幕鎖定"</string>
-    <string name="power_off" msgid="4266614107412865048">"關閉"</string>
+    <string name="power_off" msgid="4266614107412865048">"關機"</string>
     <string name="silent_mode_silent" msgid="319298163018473078">"鈴聲關閉"</string>
     <string name="silent_mode_vibrate" msgid="7072043388581551395">"鈴聲震動"</string>
     <string name="silent_mode_ring" msgid="8592241816194074353">"鈴聲開啟"</string>
@@ -225,7 +225,7 @@
     <string name="global_actions" product="tv" msgid="9091480417912345975">"Android TV 選項"</string>
     <string name="global_actions" product="default" msgid="2406416831541615258">"手機選項"</string>
     <string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
-    <string name="global_action_power_off" msgid="4471879440839879722">"關閉"</string>
+    <string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
     <string name="global_action_emergency" msgid="7112311161137421166">"緊急"</string>
     <string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
     <string name="global_action_logout" msgid="935179188218826050">"結束工作階段"</string>
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"允許應用程式讀取和寫入「請勿騷擾」設定。"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"開始查看權限使用情況"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"允許應用程式開始查看應用程式的權限使用情況 (一般應用程式並不需要)。"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"無障礙功能捷徑目標位置"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"允許應用程式定義無障礙功能捷徑目標位置。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制螢幕鎖定密碼和 PIN 所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"監控螢幕解鎖嘗試次數"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取即可停用 USB 偵錯。"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"已啟用測試工具模式"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"請將裝置回復原廠設定,以停用測試工具模式。"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"已啟用序列控制器"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"效能受到影響,勾選啟動程式即可停用。"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB 連接埠中有液體或碎片"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"USB 連接埠已自動停用。輕按即可瞭解詳情。"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"USB 連接埠可安全使用"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"未分類"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"您可以設定這些通知的重要性。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"列為重要的原因:涉及的人。"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者 (此帳戶目前已有此使用者) 嗎?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"要允許 <xliff:g id="APP">%1$s</xliff:g> 使用 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"輸入語言名稱"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1f13208..34fee2b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"允許應用程式讀取及寫入「零打擾」設定。"</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"啟動檢視權限用途"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"允許應用程式開始使用其他應用程式 (一般應用程式並不需要)。"</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"指定無障礙捷徑目標"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"允許應用程式定義指定的無障礙捷徑目標。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"管理螢幕鎖定密碼和 PIN 碼支援的字元和長度上限。"</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"監控螢幕解鎖嘗試次數"</string>
@@ -1361,10 +1363,12 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取這個選項以停用 USB 偵錯功能。"</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"測試控管工具模式已啟用"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"恢復原廠設定以停用測試控管工具模式。"</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"已啟用序列主控台"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"效能已受到影響。如要停用,請檢查系統啟動載入程式。"</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"USB 連接埠中有液體或灰塵"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"系統已自動停用 USB 連接埠。輕觸即可瞭解詳情。"</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"現在可以使用 USB 連接埠"</string>
-    <string name="usb_contaminant_not_detected_message" msgid="2415791798244545292">"手機目前無法偵測液體或灰塵。"</string>
+    <string name="usb_contaminant_not_detected_message" msgid="2415791798244545292">"手機目前沒有偵測到液體或灰塵。"</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"正在接收錯誤報告…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"要分享錯誤報告嗎?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"正在分享錯誤報告…"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"未分類"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"這些通知的重要性由你決定。"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"這則通知涉及特定人士,因此被歸為重要通知。"</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> (這個帳戶目前已有使用者) 建立新使用者嗎?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"要允許「<xliff:g id="APP">%1$s</xliff:g>」替 <xliff:g id="ACCOUNT">%2$s</xliff:g> 建立新使用者嗎?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"新增語言"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"請輸入語言名稱"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f707fcc..a5e0fed3 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -655,6 +655,8 @@
     <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Ivumela izinhlelo zokusebenza ukufunda nokubhala ukulungiswa kokuthi Ungaphazamisi."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"qala ukusetshenziswa kokubuka imvume"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"Ivumela umphathi ukuthi aqale ukusetshenziswa kwemvume kohlelo lokusebenza. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
+    <string name="permlab_accessibilityShortcutTarget" msgid="1385930065395622809">"impokophelo yesinqamuleli sokufinyeleleka"</string>
+    <string name="permdesc_accessibilityShortcutTarget" msgid="562750894417800432">"Ivumela uhlelo lokusebenza ukuthi luchaze impokophelo yesinqamuleli sokufinyeleleka."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi wokukhiya isikrini nama-PIN."</string>
     <string name="policylab_watchLogin" msgid="5091404125971980158">"Qapha imizamo yokuvula isikrini sakho"</string>
@@ -1361,6 +1363,8 @@
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string>
     <string name="test_harness_mode_notification_title" msgid="2216359742631914387">"Imodi yokuhlola i-harness inikwe amandla"</string>
     <string name="test_harness_mode_notification_message" msgid="1343197173054407119">"Yenza ukusetha kabusha kwasekuqaleni ukuze ukhubaze imodi yokuqina yokuhlola."</string>
+    <string name="console_running_notification_title" msgid="4955436518220103382">"I-serial console inikwe amandla"</string>
+    <string name="console_running_notification_message" msgid="1331995933976263865">"Ukusebenza kuyathinteka. Ukuze ukhubaze, hlola i-bootloader."</string>
     <string name="usb_contaminant_detected_title" msgid="7136400633704058349">"Uketshezi noma ama-debris kumbobo ye-USB"</string>
     <string name="usb_contaminant_detected_message" msgid="832337061059487250">"Imbobo ye-USB inqanyulwa ngokuzenzakalela. Thepha ukuze ufunde kabanzi."</string>
     <string name="usb_contaminant_not_detected_title" msgid="7708281124088684821">"KULUNGILE ukusebenzisa imbobo ye-USB"</string>
@@ -1890,10 +1894,8 @@
     <string name="default_notification_channel_label" msgid="5929663562028088222">"Akufakwanga esigabeni"</string>
     <string name="importance_from_user" msgid="7318955817386549931">"Usethe ukubaluleka kwalezi zaziso."</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Lokhu kubalulekile ngenxa yabantu ababandakanyekayo."</string>
-    <!-- no translation found for user_creation_account_exists (6559477114648176531) -->
-    <skip />
-    <!-- no translation found for user_creation_adding (9089159170398841763) -->
-    <skip />
+    <string name="user_creation_account_exists" msgid="6559477114648176531">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> (Umsebenzisi onale akhawunti usevele ukhona) ?"</string>
+    <string name="user_creation_adding" msgid="9089159170398841763">"Vumela i-<xliff:g id="APP">%1$s</xliff:g> ukuthi idale umsebenzisi omusha nge-<xliff:g id="ACCOUNT">%2$s</xliff:g> ?"</string>
     <string name="language_selection_title" msgid="2680677278159281088">"Engeza ulwimi"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Okuncamelayo kwesifunda"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Thayipha igama lolimi"</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3d0a3b3..e2f2b2c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1881,15 +1881,14 @@
   <java-symbol type="anim" name="screen_rotate_180_enter" />
   <java-symbol type="anim" name="screen_rotate_180_exit" />
   <java-symbol type="anim" name="screen_rotate_180_frame" />
+  <java-symbol type="anim" name="screen_rotate_alpha"/>
   <java-symbol type="anim" name="screen_rotate_finish_enter" />
   <java-symbol type="anim" name="screen_rotate_finish_exit" />
   <java-symbol type="anim" name="screen_rotate_finish_frame" />
   <java-symbol type="anim" name="screen_rotate_minus_90_enter" />
   <java-symbol type="anim" name="screen_rotate_minus_90_exit" />
-  <java-symbol type="anim" name="screen_rotate_minus_90_frame" />
   <java-symbol type="anim" name="screen_rotate_plus_90_enter" />
   <java-symbol type="anim" name="screen_rotate_plus_90_exit" />
-  <java-symbol type="anim" name="screen_rotate_plus_90_frame" />
   <java-symbol type="anim" name="screen_rotate_start_enter" />
   <java-symbol type="anim" name="screen_rotate_start_exit" />
   <java-symbol type="anim" name="screen_rotate_start_frame" />
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index 6ec3dc9..0ac00b8 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -173,7 +173,7 @@
         left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1);
         assertEquals(left.mLastTimeUsed, 350000);
         assertEquals(left.mLastTimeVisible, 400000);
-        assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED);
+        assertTrue(left.mActivities.indexOfKey(1) < 0);
         assertEquals(left.mTotalTimeInForeground, 350000 - 200000);
         assertEquals(left.mTotalTimeVisible, 400000 - 200000);
 
@@ -231,7 +231,7 @@
         left.update("com.test.activity1", 400000, ACTIVITY_STOPPED, 1);
         assertEquals(left.mLastTimeUsed, 300000);
         assertEquals(left.mLastTimeVisible, 400000);
-        assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED);
+        assertTrue(left.mActivities.indexOfKey(1) < 0);
         assertEquals(left.mTotalTimeInForeground, 300000 - 200000);
         assertEquals(left.mTotalTimeVisible, 400000 - 100000);
     }
@@ -249,7 +249,7 @@
         left.update("com.test.activity1", 200000, ACTIVITY_STOPPED, 1);
         assertEquals(left.mLastTimeUsed, 200000);
         assertEquals(left.mLastTimeVisible, 200000);
-        assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED);
+        assertTrue(left.mActivities.indexOfKey(1) < 0);
         assertEquals(left.mTotalTimeInForeground, 200000 - 100000);
         assertEquals(left.mTotalTimeVisible, 200000 - 100000);
 
@@ -359,14 +359,14 @@
         left.update("com.test.activity1", 550000, ACTIVITY_STOPPED, 1);
         assertEquals(left.mLastTimeUsed, 450000);
         assertEquals(left.mLastTimeVisible, 550000);
-        assertEquals(left.mActivities.get(1), ACTIVITY_STOPPED);
+        assertTrue(left.mActivities.indexOfKey(1) < 0);
         assertEquals(left.mTotalTimeInForeground, 350000);
         assertEquals(left.mTotalTimeVisible, 350000 + 100000 /*550000 - 450000*/);
 
         left.update("com.test.activity2", 650000, ACTIVITY_STOPPED, 2);
         assertEquals(left.mLastTimeUsed, 450000);
         assertEquals(left.mLastTimeVisible, 650000);
-        assertEquals(left.mActivities.get(2), ACTIVITY_STOPPED);
+        assertTrue(left.mActivities.indexOfKey(2) < 0);
         assertEquals(left.mTotalTimeInForeground, 350000);
         assertEquals(left.mTotalTimeVisible, 450000 + 100000 /*650000 - 550000*/);
     }
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index c5da549..02a88fc 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -162,8 +162,13 @@
         }
 
         @Override
-        public void internalNotifySessionLifecycle(boolean started) {
-            throw new UnsupportedOperationException("Should not have been called");
+        void internalNotifySessionResumed() {
+            throw new UnsupportedOperationException("should not have been called");
+        }
+
+        @Override
+        void internalNotifySessionPaused() {
+            throw new UnsupportedOperationException("should not have been called");
         }
 
         @Override
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index f32935f..a2402e2 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1,16 +1,2170 @@
 {
   "version": "1.0.0",
   "messages": {
-    "594230385": {
+    "-2146181682": {
+      "message": "Releasing screen wakelock, obscured by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2138637148": {
+      "message": "Clearing focused app, displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/ActivityDisplay.java"
+    },
+    "-2109864870": {
+      "message": "app-release(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2086729999": {
+      "message": "Removing app token: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-2072089308": {
+      "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2039580386": {
+      "message": "Attempted to add input method window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2024464438": {
+      "message": "app-onAnimationFinished(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2012562539": {
+      "message": "startAnimation(): Notify animation start:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2002500255": {
+      "message": "Defer removing snapshot surface in %dms",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
+    },
+    "-1991255017": {
+      "message": "Drawing snapshot surface sizeMismatch=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
+    },
+    "-1976930686": {
+      "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1963461591": {
+      "message": "Removing %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1958209312": {
+      "message": "Clear freezing of %s: hidden=%b freezing=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1953668890": {
+      "message": "Can't start recents animation, nextAppTransition=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-1949279037": {
+      "message": "Attempted to add input method window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1939358269": {
+      "message": "mRecentScreenshotAnimator finish",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1938839202": {
+      "message": "SURFACE LEAK DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1915280162": {
+      "message": "Attempted to add wallpaper window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1886298021": {
+      "message": "setAppStartingWindow: token=%s pkg=%s transferFrom=%s newTask=%b taskSwitch=%b processRunning=%b allowTaskSnapshot=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1884933373": {
+      "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1872288685": {
+      "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1868124841": {
+      "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1862269827": {
+      "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1838803135": {
+      "message": "Attempted to set windowing mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1836092044": {
+      "message": "Creating SnapshotStartingData",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1824578273": {
+      "message": "Reporting new frame to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1822611824": {
+      "message": "\tRemove token=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1797409732": {
+      "message": "Skipping %s because %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1770075711": {
+      "message": "Adding window client %s that is dead, aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1768557332": {
+      "message": "removeWallpaperAnimation()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1750206390": {
+      "message": "Exception thrown when creating surface for client %s (%s). %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1747461042": {
+      "message": "set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1741065110": {
+      "message": "No app is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1736245181": {
+      "message": "Tried to remove starting window but startingWindow was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1730156332": {
+      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1710206702": {
+      "message": "Display id=%d is frozen while keyguard locked, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1661704580": {
+      "message": "Attempted to set replacing window on non-existing app token %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1661404819": {
+      "message": "applyAnimation: atoken=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1632122349": {
+      "message": "Changing surface while display frozen: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1597650595": {
+      "message": "removeAppToken: %s delayed=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1596995693": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1587841219": {
+      "message": "Focus moving from %s to %s displayId=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1568331821": {
+      "message": "Enabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1561845439": {
+      "message": "reParentWindowToken: removing window token=%s from task=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1545962566": {
+      "message": "View server did not start",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1526645239": {
+      "message": "Timeout waiting for drawn: undrawn=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1524305318": {
+      "message": "Nulling last startingData",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1519226370": {
+      "message": "startingData was nulled out before handling mAddStartingWindow: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1515151503": {
+      "message": ">>> OPEN TRANSACTION removeReplacedWindows",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-1497837552": {
+      "message": "onAnimationFinished(): mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1483752006": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/AppWindowThumbnail.java"
+    },
+    "-1470632028": {
+      "message": "Marking app token %s with replacing windows.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1455600136": {
+      "message": "Attempted to add Dream window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1448427933": {
+      "message": "startingWindow was set but startingSurface==null, couldn't remove",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1443029505": {
+      "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1434147454": {
+      "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1427184084": {
+      "message": "addWindow: New client %s: window=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1413901262": {
+      "message": "startRecentsActivity(): intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-1391944764": {
+      "message": "SURFACE DESTROY: %s. %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-1389772804": {
+      "message": "Attempted to add voice interaction window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1350198040": {
+      "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1318134223": {
+      "message": "No longer Stopped: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1270731689": {
+      "message": "Attempted to set replacing window on app token with no content %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1270148832": {
+      "message": "Resize start waiting for draw, mDrawState=DRAW_PENDING in %s, surfaceController %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1263554915": {
+      "message": "Attempted to add Dream window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1259022216": {
+      "message": "SURFACE HIDE ( %s ): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-1257821162": {
+      "message": "OUT SURFACE %s: copied",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1219773477": {
+      "message": "setInputConsumerEnabled(%s): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1207757583": {
+      "message": "startAnimation(): Notify animation start: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1176488860": {
+      "message": "SURFACE isSecure=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-1156118957": {
+      "message": "Updated config=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-1144293044": {
+      "message": "SURFACE SET FREEZE LAYER: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-1130891072": {
+      "message": "Orientation continue waiting for draw in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-1130868271": {
+      "message": "Resizing %s WITH DRAW PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1117599386": {
+      "message": "Deferring rotation, display is not enabled.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1113134997": {
+      "message": "Attempted to add application window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1103716954": {
+      "message": "Not removing %s due to exit animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1103115659": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-1099052739": {
+      "message": "\tAdd token=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1097148233": {
+      "message": "commitVisibility: %s: hidden=%b hiddenRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1089874824": {
+      "message": "SURFACE SHOW (performLayout): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-1077196445": {
+      "message": "Add starting %s: startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-1076978367": {
+      "message": "thawRotation: mRotation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1060365734": {
+      "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1047945589": {
+      "message": "Remove client=%x, surfaceController=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1044506655": {
+      "message": "New transit away from wallpaper: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-1042574499": {
+      "message": "Attempted to add Accessibility overlay window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1009117329": {
+      "message": "isFetchingAppTransitionSpecs=true",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-1001633850": {
+      "message": "Removing focused app token:%s displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-993378225": {
+      "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DRAW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-986746907": {
+      "message": "Starting window removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-979259577": {
+      "message": "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-955458843": {
+      "message": "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-953872371": {
+      "message": "setClientHidden: %s clientHidden=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-928291778": {
+      "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-916108501": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-914253865": {
+      "message": "Attempted to add voice interaction window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-883738232": {
+      "message": "Adding more than one toast window for UID at a time.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-874446906": {
+      "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-861859917": {
+      "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-861707633": {
+      "message": "Destroying surface %s called by %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-856025122": {
+      "message": "SURFACE transparentRegionHint=%s: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-853404763": {
+      "message": "\twallpaper=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-853226675": {
+      "message": "Attempted to add window with exiting application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-809771899": {
+      "message": "findFocusedWindow: Reached focused app=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-807062773": {
+      "message": "Aborted starting %s: removed=%b startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-793346159": {
+      "message": "New transit into wallpaper: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-784959154": {
+      "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-783405930": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-771282525": {
+      "message": "Losing focus: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-760801764": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "-754503024": {
+      "message": "Relayout %s: oldVis=%d newVis=%d. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-747671114": {
+      "message": "Failed looking up window callers=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-714291355": {
+      "message": "Losing delayed focus: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-694710814": {
+      "message": "Pausing rotation during drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "-687185281": {
+      "message": "New topFocusedDisplayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-666510420": {
+      "message": "With display frozen, orientationChangeComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-666419717": {
+      "message": "Creating animation bounds layer",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-653156702": {
+      "message": "createAppAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-650040763": {
+      "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-635082269": {
+      "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-622997754": {
+      "message": "postWindowRemoveCleanupLocked: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-618015844": {
+      "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b mOnlyCore=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-583031528": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-576070986": {
+      "message": "Performing post-rotate rotation after seamless rotation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-573268667": {
+      "message": "applyAnimation: transition animation is disabled or skipped. atoken=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-554834595": {
+      "message": "Display id=%d is frozen, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-549028919": {
+      "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-545190927": {
+      "message": "<<< CLOSE TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "-519504830": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-507657818": {
+      "message": "Window %s is already added",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-496681057": {
+      "message": "Attempted to get remove mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-481924678": {
+      "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-477481651": {
+      "message": "SURFACE DESTROY PENDING: %s. %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-445944810": {
+      "message": "finish(%b): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-444624452": {
+      "message": "REPARENT from: %s to: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-439951996": {
+      "message": "Disabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-415865166": {
+      "message": "findFocusedWindow: Found new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-405536909": {
+      "message": "Removing snapshot surface",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java"
+    },
+    "-393505149": {
+      "message": "unable to update pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-386552155": {
+      "message": "Attempted to set system decors flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-379068494": {
+      "message": "unknownApps is not empty: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-371630969": {
+      "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-367797467": {
+      "message": "Creating SplashScreenStartingData",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-344488673": {
+      "message": "Finishing drawing window %s: mDrawState=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-336658140": {
+      "message": "Checking theme of starting window: 0x%x",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-324085783": {
+      "message": "SURFACE CROP %s: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-322035974": {
+      "message": "App freeze timeout expired.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-320419645": {
+      "message": "Removing replaced window: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-198463978": {
+      "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-193782861": {
+      "message": "Final remove of window: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-167822951": {
+      "message": "Attempted to add starting window to token with already existing starting window",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-129722369": {
+      "message": "New transit: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-121104356": {
+      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-117925665": {
+      "message": "addAppToken: %s task=%s at %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-116086365": {
+      "message": "******************** ENABLING SCREEN!",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-106400104": {
+      "message": "Preload recents with %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-104758113": {
+      "message": "Removing app %s delayed=%b animation=%s animating=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-96848838": {
+      "message": "Gaining focus: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-87705714": {
+      "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-87703044": {
+      "message": "Boot completed: SurfaceFlinger is dead!",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-86763148": {
+      "message": "  KILL SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "-34965929": {
+      "message": "Moving pending starting from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "-29233992": {
+      "message": "SURFACE CLEAR CROP: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-7343917": {
+      "message": "onAnimationFinished(): targetStack=%s targetActivity=%s mRestoreTargetBehindStack=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "9803449": {
+      "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "10608884": {
+      "message": "  FREEZE %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "11060725": {
+      "message": "Attempted to get system decors flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "17696244": {
+      "message": "startAnimation(): mPendingStart=%b mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "38267433": {
+      "message": "Attempted to reset replacing window on non-existing app token %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "44171776": {
+      "message": "Resetting app token %s of replacing window marks.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "51200510": {
+      "message": "  BLACK %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "51628177": {
+      "message": "Attempted to get windowing mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "83950285": {
+      "message": "removeAnimation(%d)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "91350919": {
+      "message": "Attempted to set IME flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "95281111": {
+      "message": "Attempted to get IME flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "95902367": {
+      "message": "Relayout of %s: focusMayChange=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "100936473": {
+      "message": "Wallpaper animation!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "115108840": {
+      "message": "Removing startingView=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "118187173": {
+      "message": "Enqueueing ADD_STARTING",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "123161180": {
+      "message": "SEVER CHILDREN",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "150351993": {
+      "message": "addWindow: %s startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "152914409": {
+      "message": "  BLACK %s: CREATE layer=%d",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "154699456": {
+      "message": "Last window, removing starting window %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "173419252": {
+      "message": "No thumbnail header bitmap for: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "184362060": {
+      "message": "screenshotTask(%d): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "186668272": {
+      "message": "Now changing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "194124419": {
+      "message": "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "196230599": {
+      "message": "Moving existing starting %s from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "221540118": {
+      "message": "mUserActivityTimeout set to %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "241961619": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "246676969": {
+      "message": "Attempted to add window with non-application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "248210157": {
+      "message": "Finishing remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "254883724": {
+      "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "255692476": {
+      "message": "**** GOOD TO GO",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "269576220": {
+      "message": "Resuming rotation after drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "274773837": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "285317231": {
+      "message": "Input focus has changed to %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "288485303": {
+      "message": "Attempted to set remove mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "289967521": {
+      "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "292904800": {
+      "message": "Deferring rotation, animation in progress.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "302992539": {
+      "message": "addAnimation(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "309039362": {
+      "message": "SURFACE MATRIX [%f,%f,%f,%f]: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "342460966": {
+      "message": "DRAG %s: pos=(%d,%d)",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "344795667": {
+      "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "355720268": {
+      "message": "stopFreezingDisplayLocked: Unfreezing now",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "371641947": {
+      "message": "Window Manager Crash %s",
+      "level": "WTF",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "374972436": {
+      "message": "performEnableScreen: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "385096046": {
+      "message": "Delaying loss of focus...",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "399841913": {
+      "message": "SURFACE RECOVER DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "416664944": {
+      "message": "No longer freezing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "417311568": {
+      "message": "onResize: Resizing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "424524729": {
+      "message": "Attempted to add wallpaper window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "435494046": {
+      "message": "Attempted to add window to a display for which the application does not have access: %d.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "457951957": {
+      "message": "\tNot visible=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "463993897": {
+      "message": "Aborted waiting for drawn: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "474000473": {
+      "message": "No stack above target stack=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "481370485": {
+      "message": "Computed rotation=%d for display id=%d based on lastOrientation=%d and oldRotation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "490877640": {
+      "message": "onStackOrderChanged(): stack=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "492980365": {
+      "message": "TRANSIT_TASK_OPEN_BEHIND,  adding %s to mOpeningApps",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "495032901": {
+      "message": "Expected target stack=%s to restored behind stack=%s but it is behind stack=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "508887531": {
+      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "557227556": {
+      "message": "onAnimationFinished(): Notify animation finished:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "558823034": {
+      "message": "SURFACE isOpaque=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "585096182": {
+      "message": "SURFACE isColorSpaceAgnostic=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "594260577": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "600140673": {
+      "message": "checkBootAnimationComplete: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "608694300": {
+      "message": "  NEW SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "620368427": {
+      "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "628276090": {
+      "message": "Delaying app transition for screen rotation animation to finish",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "631792420": {
+      "message": "Attempted to add window with token that is not a window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "633654009": {
+      "message": "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "644675193": {
+      "message": "Real start recents",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "646155519": {
+      "message": "Started intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "662572728": {
+      "message": "Attempted to add a toast window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "665256544": {
+      "message": "All windows drawn!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "668425960": {
+      "message": "Notify removed startingWindow %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "676824470": {
       "message": "Test completed successfully: %b %d %o %x %e %g %f %% %s.",
       "level": "ERROR",
       "group": "TEST_GROUP",
-      "at": "com\/android\/server\/wm\/ProtoLogGroup.java:94"
+      "at": "com\/android\/server\/wm\/ProtoLogGroup.java"
+    },
+    "685047360": {
+      "message": "Resizing window %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "690411811": {
+      "message": "goodToGo(): No apps to animate",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "693423992": {
+      "message": "setAnimationLocked: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "704998117": {
+      "message": "Failed to create surface control for %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "745391677": {
+      "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "758852025": {
+      "message": "Surface returned was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "765395228": {
+      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "791468751": {
+      "message": "Pausing rotation during re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "794570322": {
+      "message": "Now closing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "811802785": {
+      "message": "Changing app %s hidden=%b performLayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "829434921": {
+      "message": "Draw state now committed in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "835814848": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "845234215": {
+      "message": "App is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "847534382": {
+      "message": "Non-null appWindowToken for system window of rootType=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "853091290": {
+      "message": "Moved stack=%s behind stack=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "868946719": {
+      "message": "notifyAppResumed: wasStopped=%b %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "873914452": {
+      "message": "goodToGo()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "884043983": {
+      "message": "removeDeadWindows: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "892244061": {
+      "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "898863925": {
+      "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "913494177": {
+      "message": "removeAllWindowsIfPossible: removing win=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "916191774": {
+      "message": "Orientation change complete in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "917739349": {
+      "message": "Set focused app to: %s moveFocusNow=%b displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/ActivityDisplay.java"
+    },
+    "954470154": {
+      "message": "FORCED DISPLAY SCALING DISABLED",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "990058731": {
+      "message": "notifyAppStopped: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1001904964": {
+      "message": "***** BOOT TIMEOUT: forcing display enabled",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1004585481": {
+      "message": "%s forcing orientation to %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1021057640": {
+      "message": "Marking app token %s with replacing child windows.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1051545910": {
+      "message": "Exit animation finished in %s: remove=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1073230342": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "1089714158": {
+      "message": "  FREEZE %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "1108406230": {
+      "message": "stopFreezingDisplayLocked: Returning mWaitingForConfig=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1112047265": {
+      "message": "finishDrawingWindow: %s mDrawState=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1115417974": {
+      "message": "FORCED DISPLAY SIZE: %dx%d",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1140424002": {
+      "message": "Finished screen turning on...",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "1160771501": {
+      "message": "Resize reasons for w=%s:  %s surfaceResized=%b configChanged=%b dragResizingChanged=%b reportOrientationChanged=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1166381079": {
+      "message": "Execute app transition: %s, displayId: %d Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1195433019": {
+      "message": "Clearing startingData for token=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1208313423": {
+      "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1219600119": {
+      "message": "addWindow: win=%s Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "1220075598": {
+      "message": "SURFACE SIZE %dx%d: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "1224307091": {
+      "message": "checkBootAnimationComplete: Animation complete!",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1244668962": {
+      "message": "Added starting %s: startingWindow=%s startingView=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1288731814": {
+      "message": "WindowState.hideLw: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1325649102": {
+      "message": "Bad requesting window %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1329340614": {
+      "message": "Orientation not waiting for draw in %s, surfaceController %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1331177619": {
+      "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1358462645": {
+      "message": "Looking for focus: %s, flags=%d, canReceive=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1401700824": {
+      "message": "Window drawn win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1404220922": {
+      "message": "Translucent=%s Floating=%s ShowWallpaper=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1422781269": {
+      "message": "Resuming rotation after re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "1423418408": {
+      "message": "unable to restore pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1423592961": {
+      "message": "<<< CLOSE TRANSACTION removeReplacedWindows",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "1430336882": {
+      "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1434383382": {
+      "message": "Attempted to get flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1448683958": {
+      "message": "Override pending remote transitionSet=%b adapter=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "1457990604": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "1469292670": {
+      "message": "Changing focus from %s to %s displayId=%d Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1495525537": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "1496418389": {
+      "message": "Removing starting %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1497304204": {
+      "message": "Deferring rotation, rotation is paused.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "1504168072": {
+      "message": "removeIfPossible: %s callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1518495446": {
+      "message": "removeWindowToken: Attempted to remove non-existing token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1519757176": {
+      "message": "setHomeApp(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "1521476038": {
+      "message": "Attempted to set flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1525976603": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "1531527061": {
+      "message": "createAnimationAdapter(): token=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1563755163": {
+      "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1573332272": {
+      "message": "Display id=%d selected orientation %d, got rotation %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "1577579529": {
+      "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1589610525": {
+      "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "1628345525": {
+      "message": "Now opening app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1634557978": {
+      "message": "**** Dismissing screen rotation animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1635462459": {
+      "message": "onMovedByResize: Moving %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1637745145": {
+      "message": "Clear freezing of %s force=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1720696061": {
+      "message": "Adding window to Display that has been removed.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1739298851": {
+      "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1747941491": {
+      "message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "1756082882": {
+      "message": "Orientation change skips hidden %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "1762317752": {
+      "message": "Expected target stack=%s to be top most but found stack=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "1764592478": {
+      "message": "reparent: moving app token=%s to task=%d at %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1774661765": {
+      "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1814552834": {
+      "message": "performLayout: App token exiting now removed %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1836306327": {
+      "message": "Skipping set freeze of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1865125884": {
+      "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "1865246212": {
+      "message": "\tapp=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1866772666": {
+      "message": "SAFE MODE not enabled",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1878395049": {
+      "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1883987026": {
+      "message": "removeAppToken make exiting: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "1891501279": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1921821199": {
+      "message": "Preserving %s until the new one is added",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1947239194": {
+      "message": "Deferring rotation, still finishing previous rotation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "1964565370": {
+      "message": "Starting remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1984470582": {
+      "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/TaskScreenshotAnimatable.java"
+    },
+    "1984738415": {
+      "message": "Now animating app in place %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1984782949": {
+      "message": ">>> OPEN TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "1993685727": {
+      "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "2016061474": {
+      "message": "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "2018454757": {
+      "message": "WS.removeImmediately: %s Already removed...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "2028163120": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "2034780299": {
+      "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2045641491": {
+      "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "2054958632": {
+      "message": "Schedule remove starting %s startingWindow=%s startingView=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "2057434754": {
+      "message": "\tvisible=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "2076259606": {
+      "message": "Finish starting %s: first real window is shown, no animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/AppWindowToken.java"
+    },
+    "2083556954": {
+      "message": "Set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2086878461": {
+      "message": "Could not send command %s with parameters %s. %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2088592090": {
+      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "2096635066": {
+      "message": "Acquiring screen wakelock due to %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2114149926": {
+      "message": "Not removing %s because app died while it's visible",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "2128604122": {
+      "message": "findFocusedWindow: No focusable windows.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2128917433": {
+      "message": "onProposedRotationChanged, rotation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "2137411379": {
+      "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
     }
   },
   "groups": {
     "TEST_GROUP": {
       "tag": "WindowManagetProtoLogTest"
+    },
+    "WM_DEBUG_ADD_REMOVE": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_APP_TRANSITIONS": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_APP_TRANSITIONS_ANIM": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_BOOT": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_DRAW": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_FOCUS": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_FOCUS_LIGHT": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_KEEP_SCREEN_ON": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_ORIENTATION": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_RECENTS_ANIMATIONS": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_REMOTE_ANIMATIONS": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_RESIZE": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_SCREEN_ON": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_STARTING_WINDOW": {
+      "tag": "WindowManager"
+    },
+    "WM_DEBUG_WINDOW_MOVEMENT": {
+      "tag": "WindowManager"
+    },
+    "WM_ERROR": {
+      "tag": "WindowManager"
+    },
+    "WM_SHOW_SURFACE_ALLOC": {
+      "tag": "WindowManager"
+    },
+    "WM_SHOW_TRANSACTIONS": {
+      "tag": "WindowManager"
     }
   }
 }
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 072beae..c692097 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -323,14 +323,16 @@
         <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
     </family>
     <family lang="und-Mymr" variant="elegant">
-        <font weight="400" style="normal">NotoSansMyanmar-Regular-ZawDecode.ttf</font>
-        <font weight="700" style="normal">NotoSansMyanmar-Bold-ZawDecode.ttf</font>
+        <font weight="400" style="normal">NotoSansMyanmar-Regular.otf</font>
+        <font weight="500" style="normal">NotoSansMyanmar-Medium.otf</font>
+        <font weight="700" style="normal">NotoSansMyanmar-Bold.otf</font>
         <font weight="400" style="normal" fallbackFor="serif">NotoSerifMyanmar-Regular.otf</font>
         <font weight="700" style="normal" fallbackFor="serif">NotoSerifMyanmar-Bold.otf</font>
     </family>
     <family lang="und-Mymr" variant="compact">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular-ZawDecode.ttf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold-ZawDecode.ttf</font>
+        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.otf</font>
+        <font weight="500" style="normal">NotoSansMyanmarUI-Medium.otf</font>
+        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font>
     </family>
     <family lang="und-Thaa">
         <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 01caf01..eec49df 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -224,6 +224,62 @@
   return &loaded_package->GetOverlayableMap();
 }
 
+bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name,
+                                            std::string* out) const {
+  uint8_t package_id = 0U;
+  for (const auto& apk_assets : apk_assets_) {
+    const LoadedArsc* loaded_arsc = apk_assets->GetLoadedArsc();
+    if (loaded_arsc == nullptr) {
+      continue;
+    }
+
+    const auto& loaded_packages = loaded_arsc->GetPackages();
+    if (loaded_packages.empty()) {
+      continue;
+    }
+
+    const auto& loaded_package = loaded_packages[0];
+    if (loaded_package->GetPackageName() == package_name) {
+      package_id = GetAssignedPackageId(loaded_package.get());
+      break;
+    }
+  }
+
+  if (package_id == 0U) {
+    ANDROID_LOG(ERROR) << base::StringPrintf("No package with name '%s", package_name.data());
+    return false;
+  }
+
+  const size_t idx = package_ids_[package_id];
+  if (idx == 0xff) {
+    return false;
+  }
+
+  std::string output;
+  for (const ConfiguredPackage& package : package_groups_[idx].packages_) {
+    const LoadedPackage* loaded_package = package.loaded_package_;
+    for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
+      const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
+      if (info != nullptr) {
+        ResourceName res_name;
+        if (!GetResourceName(*it, &res_name)) {
+          ANDROID_LOG(ERROR) << base::StringPrintf(
+              "Unable to retrieve name of overlayable resource 0x%08x", *it);
+          return false;
+        }
+
+        const std::string name = ToFormattedResourceString(&res_name);
+        output.append(base::StringPrintf(
+            "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
+            name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
+      }
+    }
+  }
+
+  *out = std::move(output);
+  return true;
+}
+
 void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
   const int diff = configuration_.diff(configuration);
   configuration_ = configuration;
@@ -1073,7 +1129,7 @@
   }
 }
 
-uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) {
+uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
   for (auto& package_group : package_groups_) {
     for (auto& package2 : package_group.packages_) {
       if (package2.loaded_package_ == package) {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 1e2b36cb1..de46081 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -124,6 +124,10 @@
   // This may be nullptr if the APK represented by `cookie` has no resource table.
   const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;
 
+  // Returns a string representation of the overlayable API of a package.
+  bool GetOverlayablesToString(const android::StringPiece& package_name,
+                               std::string* out) const;
+
   const std::unordered_map<std::string, std::string>*
     GetOverlayableMapForPackage(uint32_t package_id) const;
 
@@ -308,7 +312,7 @@
   const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);
 
   // Retrieve the assigned package id of the package if loaded into this AssetManager
-  uint8_t GetAssignedPackageId(const LoadedPackage* package);
+  uint8_t GetAssignedPackageId(const LoadedPackage* package) const;
 
   // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
   // have a longer lifetime.
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 40c8e46..1591024 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -707,7 +707,7 @@
   EXPECT_EQ("", resultDisabled);
 }
 
-TEST_F(AssetManager2Test, GetOverlayableMap) {
+TEST_F(AssetManager2Test, GetOverlayablesToString) {
   ResTable_config desired_config;
   memset(&desired_config, 0, sizeof(desired_config));
 
@@ -721,6 +721,12 @@
   ASSERT_EQ(2, map->size());
   ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme");
   ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable");
+
+  std::string api;
+  ASSERT_TRUE(assetmanager.GetOverlayablesToString("com.android.overlayable", &api));
+  ASSERT_EQ(api.find("not_overlayable"), std::string::npos);
+  ASSERT_NE(api.find("resource='com.android.overlayable:string/overlayable2' overlayable='OverlayableResources1' actor='overlay://theme' policy='0x0000000a'\n"),
+            std::string::npos);
 }
 
 }  // namespace android
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index b017384..f839213e 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -43,41 +43,28 @@
     if (!matrix.rectStaysRect()) return true;
     SkRect dstDevRect = matrix.mapRect(dstRect);
     float dstW, dstH;
-    bool requiresIntegerTranslate = false;
     if (MathUtils::isZero(matrix.getScaleX()) && MathUtils::isZero(matrix.getScaleY())) {
         // Has a 90 or 270 degree rotation, although total matrix may also have scale factors
         // in m10 and m01. Those scalings are automatically handled by mapRect so comparing
         // dimensions is sufficient, but swap width and height comparison.
         dstW = dstDevRect.height();
         dstH = dstDevRect.width();
-        requiresIntegerTranslate = true;
     } else {
         // Handle H/V flips or 180 rotation matrices. Axes may have been mirrored, but
         // dimensions are still safe to compare directly.
         dstW = dstDevRect.width();
         dstH = dstDevRect.height();
-        requiresIntegerTranslate =
-                matrix.getScaleX() < -NON_ZERO_EPSILON || matrix.getScaleY() < -NON_ZERO_EPSILON;
     }
     if (!(MathUtils::areEqual(dstW, srcRect.width()) &&
           MathUtils::areEqual(dstH, srcRect.height()))) {
         return true;
     }
-    if (requiresIntegerTranslate) {
-        // Device rect and source rect should be integer aligned to ensure there's no difference
-        // in how nearest-neighbor sampling is resolved.
-        return !(isIntegerAligned(srcRect.x()) &&
-                 isIntegerAligned(srcRect.y()) &&
-                 isIntegerAligned(dstDevRect.x()) &&
-                 isIntegerAligned(dstDevRect.y()));
-    } else {
-        // As long as src and device rects are translated by the same fractional amount,
-        // filtering won't be needed
-        return !(MathUtils::areEqual(SkScalarFraction(srcRect.x()),
-                                     SkScalarFraction(dstDevRect.x())) &&
-                 MathUtils::areEqual(SkScalarFraction(srcRect.y()),
-                                     SkScalarFraction(dstDevRect.y())));
-    }
+    // Device rect and source rect should be integer aligned to ensure there's no difference
+    // in how nearest-neighbor sampling is resolved.
+    return !(isIntegerAligned(srcRect.x()) &&
+             isIntegerAligned(srcRect.y()) &&
+             isIntegerAligned(dstDevRect.x()) &&
+             isIntegerAligned(dstDevRect.y()));
 }
 
 bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 684dc22..30cc007 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -491,9 +491,9 @@
                 swap.dequeueDuration = 0;
             } else {
                 swap.dequeueDuration =
-                        us2ns(ANativeWindow_getLastDequeueDuration(mNativeSurface.get()));
+                        ANativeWindow_getLastDequeueDuration(mNativeSurface.get());
             }
-            swap.queueDuration = us2ns(ANativeWindow_getLastQueueDuration(mNativeSurface.get()));
+            swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get());
         } else {
             swap.dequeueDuration = 0;
             swap.queueDuration = 0;
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 16f2917..6bb896fd 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -20,11 +20,11 @@
     ],
 
     shared_libs: [
+        "libandroid_runtime",
         "libbinder",
         "libcutils",
         "liblog",
         "libutils",
-        "libhwui",
         "libgui",
         "libui",
         "libinput",
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index abf0837..e4348f2 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -24,12 +24,6 @@
 
 #include <log/log.h>
 
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkPaint.h>
-#include <SkBlendMode.h>
-
 namespace android {
 
 // --- WeakLooperCallback ---
diff --git a/libs/input/SpriteController.cpp b/libs/input/SpriteController.cpp
index fd386e9..804644c 100644
--- a/libs/input/SpriteController.cpp
+++ b/libs/input/SpriteController.cpp
@@ -23,11 +23,9 @@
 #include <utils/String8.h>
 #include <gui/Surface.h>
 
-#include <SkBitmap.h>
-#include <SkCanvas.h>
-#include <SkColor.h>
-#include <SkPaint.h>
-
+#include <android/graphics/bitmap.h>
+#include <android/graphics/canvas.h>
+#include <android/graphics/paint.h>
 #include <android/native_window.h>
 
 namespace android {
@@ -132,8 +130,8 @@
         SpriteUpdate& update = updates.editItemAt(i);
 
         if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
-            update.state.surfaceWidth = update.state.icon.bitmap.width();
-            update.state.surfaceHeight = update.state.icon.bitmap.height();
+            update.state.surfaceWidth = update.state.icon.bitmap.getInfo().width;
+            update.state.surfaceHeight = update.state.icon.bitmap.getInfo().height;
             update.state.surfaceDrawn = false;
             update.state.surfaceVisible = false;
             update.state.surfaceControl = obtainSurface(
@@ -154,8 +152,8 @@
         }
 
         if (update.state.wantSurfaceVisible()) {
-            int32_t desiredWidth = update.state.icon.bitmap.width();
-            int32_t desiredHeight = update.state.icon.bitmap.height();
+            int32_t desiredWidth = update.state.icon.bitmap.getInfo().width;
+            int32_t desiredHeight = update.state.icon.bitmap.getInfo().height;
             if (update.state.surfaceWidth < desiredWidth
                     || update.state.surfaceHeight < desiredHeight) {
                 needApplyTransaction = true;
@@ -201,26 +199,22 @@
             if (status) {
                 ALOGE("Error %d locking sprite surface before drawing.", status);
             } else {
-                SkBitmap surfaceBitmap;
-                ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
-                surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height),
-                                            outBuffer.bits, bpr);
+                graphics::Paint paint;
+                paint.setBlendMode(ABLEND_MODE_SRC);
 
-                SkCanvas surfaceCanvas(surfaceBitmap);
+                graphics::Canvas canvas(outBuffer, (int32_t) surface->getBuffersDataSpace());
+                canvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
 
-                SkPaint paint;
-                paint.setBlendMode(SkBlendMode::kSrc);
-                surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);
+                const int iconWidth = update.state.icon.bitmap.getInfo().width;
+                const int iconHeight = update.state.icon.bitmap.getInfo().height;
 
-                if (outBuffer.width > update.state.icon.bitmap.width()) {
-                    paint.setColor(0); // transparent fill color
-                    surfaceCanvas.drawRect(SkRect::MakeLTRB(update.state.icon.bitmap.width(), 0,
-                            outBuffer.width, update.state.icon.bitmap.height()), paint);
+                if (outBuffer.width > iconWidth) {
+                    paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent
+                    canvas.drawRect({iconWidth, 0, outBuffer.width, iconHeight}, paint);
                 }
-                if (outBuffer.height > update.state.icon.bitmap.height()) {
-                    paint.setColor(0); // transparent fill color
-                    surfaceCanvas.drawRect(SkRect::MakeLTRB(0, update.state.icon.bitmap.height(),
-                            outBuffer.width, outBuffer.height), paint);
+                if (outBuffer.height > iconHeight) {
+                    paint.setBlendMode(ABLEND_MODE_CLEAR); // clear to transparent
+                    canvas.drawRect({0, iconHeight, outBuffer.width, outBuffer.height}, paint);
                 }
 
                 status = surface->unlockAndPost();
@@ -398,12 +392,7 @@
 
     uint32_t dirty;
     if (icon.isValid()) {
-        SkBitmap* bitmapCopy = &mLocked.state.icon.bitmap;
-        if (bitmapCopy->tryAllocPixels(icon.bitmap.info().makeColorType(kN32_SkColorType))) {
-            icon.bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
-                    bitmapCopy->rowBytes(), 0, 0);
-        }
-
+        mLocked.state.icon.bitmap = icon.bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888);
         if (!mLocked.state.icon.isValid()
                 || mLocked.state.icon.hotSpotX != icon.hotSpotX
                 || mLocked.state.icon.hotSpotY != icon.hotSpotY) {
diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h
index 79a904f..2513544 100644
--- a/libs/input/SpriteController.h
+++ b/libs/input/SpriteController.h
@@ -20,10 +20,9 @@
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
 
+#include <android/graphics/bitmap.h>
 #include <gui/SurfaceComposerClient.h>
 
-#include <SkBitmap.h>
-
 namespace android {
 
 /*
@@ -56,21 +55,16 @@
  */
 struct SpriteIcon {
     inline SpriteIcon() : style(0), hotSpotX(0), hotSpotY(0) { }
-    inline SpriteIcon(const SkBitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) :
+    inline SpriteIcon(const graphics::Bitmap& bitmap, int32_t style, float hotSpotX, float hotSpotY) :
             bitmap(bitmap), style(style), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { }
 
-    SkBitmap bitmap;
+    graphics::Bitmap bitmap;
     int32_t style;
     float hotSpotX;
     float hotSpotY;
 
     inline SpriteIcon copy() const {
-        SkBitmap bitmapCopy;
-        if (bitmapCopy.tryAllocPixels(bitmap.info().makeColorType(kN32_SkColorType))) {
-            bitmap.readPixels(bitmapCopy.info(), bitmapCopy.getPixels(), bitmapCopy.rowBytes(),
-                    0, 0);
-        }
-        return SpriteIcon(bitmapCopy, style, hotSpotX, hotSpotY);
+        return SpriteIcon(bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888), style, hotSpotX, hotSpotY);
     }
 
     inline void reset() {
@@ -81,7 +75,7 @@
     }
 
     inline bool isValid() const {
-        return !bitmap.isNull() && !bitmap.empty();
+        return bitmap.isValid() && !bitmap.isEmpty();
     }
 };
 
@@ -183,7 +177,7 @@
      * This structure is designed so that it can be copied during updates so that
      * surfaces can be resized and redrawn without blocking the client by holding a lock
      * on the sprites for a long time.
-     * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
+     * Note that the SpriteIcon holds a reference to a shared (and immutable) bitmap. */
     struct SpriteState {
         inline SpriteState() :
                 dirty(0), visible(false),
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index e83b2a7..b1e3d6f 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -18,9 +18,9 @@
         "PointerController_test.cpp",
     ],
     shared_libs: [
+        "libandroid_runtime",
         "libinputservice",
         "libgui",
-        "libhwui",
         "libutils",
     ],
     static_libs: [
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6b47d1d..68480ce 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -27,7 +27,6 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresFeature;
 import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -134,23 +133,27 @@
     /**
      * This key is no longer in use.
      *
-     * Key used for a Bundle extra holding an Integer status value
-     * when a status change is broadcast using a PendingIntent.
+     * <p>Key used for a Bundle extra holding an Integer status value when a status change is
+     * broadcast using a PendingIntent.
      *
-     * @deprecated Status changes are deprecated and no longer broadcast.
+     * @deprecated Status changes are deprecated and no longer broadcast from Android Q onwards.
      */
     @Deprecated
     public static final String KEY_STATUS_CHANGED = "status";
 
     /**
-     * Key used for a Bundle extra holding an Boolean status value
-     * when a provider enabled/disabled event is broadcast using a PendingIntent.
+     * Key used for an extra holding a boolean enabled/disabled status value when a provider
+     * enabled/disabled event is broadcast using a PendingIntent.
+     *
+     * @see #requestLocationUpdates(String, long, long, PendingIntent)
      */
     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
 
     /**
-     * Key used for a Bundle extra holding a Location value
-     * when a location change is broadcast using a PendingIntent.
+     * Key used for an extra holding a {@link Location} value when a location change is broadcast
+     * using a PendingIntent.
+     *
+     * @see #requestLocationUpdates(String, long, long, PendingIntent)
      */
     public static final String KEY_LOCATION_CHANGED = "location";
 
@@ -382,7 +385,7 @@
     }
 
     /**
-     * Returns the current enabled/disabled state of location.
+     * Returns the current enabled/disabled state of location for the given user.
      *
      * @param userHandle the user to query
      * @return true if location is enabled and false if location is disabled.
@@ -399,7 +402,7 @@
     }
 
     /**
-     * Enables or disables the location setting.
+     * Enables or disables location for the given user.
      *
      * @param enabled true to enable location and false to disable location.
      * @param userHandle the user to set
@@ -455,7 +458,7 @@
     @SystemApi
     public boolean isProviderEnabledForUser(
             @NonNull String provider, @NonNull UserHandle userHandle) {
-        checkProvider(provider);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
 
         try {
             return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
@@ -484,7 +487,7 @@
     @RequiresPermission(WRITE_SECURE_SETTINGS)
     public boolean setProviderEnabledForUser(
             @NonNull String provider, boolean enabled, @NonNull UserHandle userHandle) {
-        checkProvider(provider);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
 
         return Settings.Secure.putStringForUser(
                 mContext.getContentResolver(),
@@ -494,57 +497,45 @@
     }
 
     /**
-     * Get the last known location.
+     * Gets the last known location from the fused provider, or null if there is no last known
+     * location. The returned location may be quite old in some circumstances, so the age of the
+     * location should always be checked.
      *
-     * <p>This location could be very old so use
-     * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can
-     * also return null if no previous location is available.
-     *
-     * <p>Always returns immediately.
-     *
-     * @return The last known location, or null if not available
-     * @throws SecurityException if no suitable permission is present
+     * @return the last known location, or null if not available
+     * @throws SecurityException if no suitable location permission is present
      *
      * @hide
      */
     @Nullable
+    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public Location getLastLocation() {
-        String packageName = mContext.getPackageName();
-
         try {
-            return mService.getLastLocation(null, packageName);
+            return mService.getLastLocation(null, mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Returns a Location indicating the data from the last known
-     * location fix obtained from the given provider.
-     *
-     * <p> This can be done
-     * without starting the provider.  Note that this location could
-     * be out-of-date, for example if the device was turned off and
-     * moved to another location.
-     *
-     * <p> If the provider is currently disabled, null is returned.
+     * Gets the last known location from the given provider, or null if there is no last known
+     * location. The returned location may be quite old in some circumstances, so the age of the
+     * location should always be checked.
      *
      * @param provider the name of the provider
-     * @return the last known location for the provider, or null
-     *
+     * @return the last known location for the given provider, or null if not available
      * @throws SecurityException if no suitable permission is present
      * @throws IllegalArgumentException if provider is null or doesn't exist
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     @Nullable
     public Location getLastKnownLocation(@NonNull String provider) {
-        checkProvider(provider);
-        String packageName = mContext.getPackageName();
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                 provider, 0, 0, true);
 
         try {
-            return mService.getLastLocation(request, packageName);
+            return mService.getLastLocation(request, mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -554,7 +545,7 @@
      * Register for a single location update using the named provider and
      * a callback.
      *
-     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)}
      * for more detail on how to use this method.
      *
      * @param provider the name of the provider with which to register
@@ -568,12 +559,16 @@
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
+     * @deprecated This method can drain much more battery than expected if it is not possible to
+     * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
+     * removal.
      */
+    @Deprecated
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(
             @NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper) {
-        checkProvider(provider);
-        checkListener(listener);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
                 provider, 0, 0, true);
@@ -599,14 +594,17 @@
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
+     * @deprecated This method can drain much more battery than expected if it is not possible to
+     * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
+     * removal.
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(
             @NonNull Criteria criteria,
             @NonNull LocationListener listener,
             @Nullable Looper looper) {
-        checkCriteria(criteria);
-        checkListener(listener);
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
                 criteria, 0, 0, true);
@@ -625,10 +623,13 @@
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
      * @throws SecurityException if no suitable permission is present
+     * @deprecated This method can drain much more battery than expected if it is not possible to
+     * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
+     * removal.
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(@NonNull String provider, @NonNull PendingIntent intent) {
-        checkProvider(provider);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
         checkPendingIntent(intent);
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
@@ -649,10 +650,13 @@
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if intent is null
      * @throws SecurityException if no suitable permission is present
+     * @deprecated This method can drain much more battery than expected if it is not possible to
+     * calculate location. Prefer any of the requestLocationUpdates() methods which require explicit
+     * removal.
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestSingleUpdate(@NonNull Criteria criteria, @NonNull PendingIntent intent) {
-        checkCriteria(criteria);
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
         checkPendingIntent(intent);
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
@@ -661,84 +665,121 @@
     }
 
     /**
-     * Register for location updates using the named provider, and a
-     * pending intent.
+     * Register for location updates from the given provider with the given arguments. {@link
+     * LocationListener} callbacks will take place on the given {@link Looper} or {@link Executor}.
+     * If a null {@link Looper} is supplied, the Looper of the calling thread will be used instead.
+     * Only one request can be registered for each unique listener, so any subsequent requests with
+     * the same listener will overwrite all associated arguments.
      *
-     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
-     * for more detail on how to use this method.
+     * <p> It may take a while to receive the first location update. If an immediate location is
+     * required, applications may use the {@link #getLastKnownLocation(String)} method.
+     *
+     * <p> The location update interval can be controlled using the minimum time parameter. The
+     * elapsed time between location updates will never be less than this parameter, although it may
+     * be more depending on location availability and other factors. Choosing a sensible value for
+     * the minimum time parameter is important to conserve battery life. Every location update
+     * requires power from a variety of sensors. Select a minimum time parameter as high as possible
+     * while still providing a reasonable user experience. If your application is not in the
+     * foreground and showing location to the user then your application should consider switching
+     * to the {@link #PASSIVE_PROVIDER} instead.
+     *
+     * <p> The minimum distance parameter can also be used to control the frequency of location
+     * updates. If it is greater than 0 then the location provider will only send your application
+     * an update when the location has changed by at least minDistance meters, AND when the minimum
+     * time has elapsed. However it is more difficult for location providers to save power using the
+     * minimum distance parameter, so the minimum time parameter should be the primary tool for
+     * conserving battery life.
+     *
+     * <p> If your application wants to passively observe location updates triggered by other
+     * applications, but not consume any additional power otherwise, then use the {@link
+     * #PASSIVE_PROVIDER}. This provider does not turn on or modify active location providers, so
+     * you do not need to be as careful about minimum time and minimum distance parameters. However,
+     * if your application performs heavy work on a location update (such as network activity) then
+     * you should select non-zero values for the parameters to rate-limit your update frequency in
+     * the case another application enables a location provider with extremely fast updates.
+     *
+     * <p>In case the provider you have selected is disabled, location updates will cease, and a
+     * provider availability update will be sent. As soon as the provider is enabled again, another
+     * provider availability update will be sent and location updates will immediately resume.
+     *
+     * <p> When location callbacks are invoked, the system will hold a wakelock on your
+     * application's behalf for some period of time, but not indefinitely. If your application
+     * requires a long running wakelock within the location callback, you should acquire it
+     * yourself.
+     *
+     * <p class="note"> Prior to Jellybean, the minTime parameter was only a hint, and some location
+     * provider implementations ignored it. For Jellybean and onwards however, it is mandatory for
+     * Android compatible devices to observe both the minTime and minDistance parameters.
+     *
+     * <p>To unregister for location updates, use {@link #removeUpdates(LocationListener)}.
      *
      * @param provider the name of the provider with which to register
-     * @param minTime minimum time interval between location updates, in milliseconds
-     * @param minDistance minimum distance between location updates, in meters
-     * @param listener a {@link LocationListener} whose
-     * {@link LocationListener#onLocationChanged} method will be called for
-     * each location update
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param listener the listener to receive location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
-     * on this device
      * @throws IllegalArgumentException if listener is null
      * @throws RuntimeException if the calling thread has no Looper
      * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance,
+    public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
             @NonNull LocationListener listener) {
-        checkProvider(provider);
-        checkListener(listener);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
-                provider, minTime, minDistance, false);
+                provider, minTimeMs, minDistanceM, false);
         requestLocationUpdates(request, listener, null);
     }
 
     /**
      * Register for location updates using the named provider, and a callback on
-     * the specified looper thread.
+     * the specified {@link Looper}.
      *
-     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
-     * for more detail on how to use this method.
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
      * @param provider the name of the provider with which to register
-     * @param minTime minimum time interval between location updates, in milliseconds
-     * @param minDistance minimum distance between location updates, in meters
-     * @param listener a {@link LocationListener} whose
-     * {@link LocationListener#onLocationChanged} method will be called for
-     * each location update
-     * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the calling
-     * thread
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param listener the listener to receive location updates
+     * @param looper the looper handling listener callbacks, or null to use the looper of the
+     *               calling thread
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance,
+    public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
             @NonNull LocationListener listener, @Nullable Looper looper) {
-        checkProvider(provider);
-        checkListener(listener);
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
-                provider, minTime, minDistance, false);
+                provider, minTimeMs, minDistanceM, false);
         requestLocationUpdates(request, listener, looper);
     }
 
     /**
-     * Register for location updates from the given provider with the given arguments. {@link
-     * LocationListener} callbacks will take place on the given {@link Executor}. Only one request
-     * can be registered for each unique listener, so any subsequent requests with the same listener
-     * will overwrite all associated arguments.
+     * Register for location updates using the named provider, and a callback on
+     * the specified {@link Executor}.
      *
-     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener, Looper)} for
-     * more information.
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
-     * @param provider     the name of the provider used for location updates
-     * @param minTimeMs    minimum time interval between location updates, in milliseconds
-     * @param minDistanceM minimum distance between location updates, in meters
-     * @param executor     all listener updates will take place on this {@link Executor}
-     * @param listener     a {@link LocationListener} that will be called when updates are available
-     * @throws IllegalArgumentException if provider, listener, or looper is null or nonexistant
-     * @throws SecurityException        if no suitable permission is present
+     * @param provider the name of the provider with which to register
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param executor the executor handling listener callbacks
+     * @param listener the listener to receive location updates
+     *
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if executor is null
+     * @throws IllegalArgumentException if listener is null
+     * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestLocationUpdates(
@@ -753,50 +794,49 @@
     }
 
     /**
-     * Register for location updates using a Criteria, and a callback
-     * on the specified looper thread.
+     * Register for location updates using a provider selected through the given Criteria, and a
+     * callback on the specified {@link Looper}.
      *
-     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
-     * for more detail on how to use this method.
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
-     * @param minTime minimum time interval between location updates, in milliseconds
-     * @param minDistance minimum distance between location updates, in meters
-     * @param criteria contains parameters for the location manager to choose the
-     * appropriate provider and parameters to compute the location
-     * @param listener a {@link LocationListener} whose
-     * {@link LocationListener#onLocationChanged} method will be called for
-     * each location update
-     * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the calling
-     * thread
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param criteria contains parameters to choose the appropriate provider for location updates
+     * @param listener the listener to receive location updates
      *
      * @throws IllegalArgumentException if criteria is null
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(long minTime, float minDistance, @NonNull Criteria criteria,
-            @NonNull LocationListener listener, @Nullable Looper looper) {
-        checkCriteria(criteria);
-        checkListener(listener);
+    public void requestLocationUpdates(long minTimeMs, float minDistanceM,
+            @NonNull Criteria criteria, @NonNull LocationListener listener,
+            @Nullable Looper looper) {
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+        Preconditions.checkArgument(listener != null, "invalid null listener");
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
-                criteria, minTime, minDistance, false);
+                criteria, minTimeMs, minDistanceM, false);
         requestLocationUpdates(request, listener, looper);
     }
 
     /**
-     * Uses the given {@link Criteria} to select a single provider to use for location updates.
+     * Register for location updates using a provider selected through the given Criteria, and a
+     * callback on the specified {@link Executor}.
      *
-     * <p>See {@link #requestLocationUpdates(String, long, float, Executor, LocationListener)} for
-     * more information.
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
-     * @param minTimeMs    minimum time interval between location updates, in milliseconds
-     * @param minDistanceM minimum distance between location updates, in meters
-     * @param criteria     the {@link Criteria} used to select a provider for location updates
-     * @param executor     all listener updates will take place on this {@link Executor}
-     * @param listener     a {@link LocationListener} that will be called when updates are available
-     * @throws IllegalArgumentException if criteria, listener, or looper is null
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param criteria contains parameters to choose the appropriate provider for location updates
+     * @param executor the executor handling listener callbacks
+     * @param listener the listener to receive location updates
+     *
+     * @throws IllegalArgumentException if criteria is null
+     * @throws IllegalArgumentException if executor is null
+     * @throws IllegalArgumentException if listener is null
      * @throws SecurityException        if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
@@ -812,191 +852,81 @@
     }
 
     /**
-     * Register for location updates using the named provider, and a
-     * pending intent.
+     * Register for location updates using the named provider, and callbacks delivered via the
+     * provided {@link PendingIntent}.
      *
-     * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
-     * for more detail on how to use this method.
+     * <p>The delivered pending intents will contain extras with the callback information. The keys
+     * used for the extras are {@link #KEY_LOCATION_CHANGED} and {@link #KEY_PROVIDER_ENABLED}. See
+     * the documentation for each respective extra key for information on the values.
+     *
+     * <p>To unregister for location updates, use {@link #removeUpdates(PendingIntent)}.
+     *
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
      * @param provider the name of the provider with which to register
-     * @param minTime minimum time interval between location updates, in milliseconds
-     * @param minDistance minimum distance between location updates, in meters
-     * @param intent a {@link PendingIntent} to be sent for each location update
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param pendingIntent the pending intent to send location updates
      *
      * @throws IllegalArgumentException if provider is null or doesn't exist
-     * on this device
-     * @throws IllegalArgumentException if intent is null
+     * @throws IllegalArgumentException if pendingIntent is null
      * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(@NonNull String provider, long minTime, float minDistance,
-            @NonNull PendingIntent intent) {
-        checkProvider(provider);
-        checkPendingIntent(intent);
+    public void requestLocationUpdates(@NonNull String provider, long minTimeMs, float minDistanceM,
+            @NonNull PendingIntent pendingIntent) {
+        Preconditions.checkArgument(provider != null, "invalid null provider");
+        checkPendingIntent(pendingIntent);
 
         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
-                provider, minTime, minDistance, false);
-        requestLocationUpdates(request, intent);
+                provider, minTimeMs, minDistanceM, false);
+        requestLocationUpdates(request, pendingIntent);
     }
 
     /**
-     * Register for location updates using a Criteria and pending intent.
+     * Register for location updates using a provider selected through the given Criteria, and
+     * callbacks delivered via the provided {@link PendingIntent}.
      *
-     * <p>The <code>requestLocationUpdates()</code> and
-     * <code>requestSingleUpdate()</code> register the current activity to be
-     * updated periodically by the named provider, or by the provider matching
-     * the specified {@link Criteria}, with location and status updates.
+     * <p>See {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on
+     * how this method works.
      *
-     * <p> It may take a while to receive the first location update. If
-     * an immediate location is required, applications may use the
-     * {@link #getLastKnownLocation(String)} method.
+     * @param minTimeMs minimum time interval between location updates in milliseconds
+     * @param minDistanceM minimum distance between location updates in meters
+     * @param criteria contains parameters to choose the appropriate provider for location updates
+     * @param pendingIntent the pending intent to send location updates
      *
-     * <p> Location updates are received either by {@link LocationListener}
-     * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.
-     *
-     * <p> If the caller supplied a pending intent, then location updates
-     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
-     * {@link android.location.Location} value.
-     *
-     * <p> The location update interval can be controlled using the minTime parameter.
-     * The elapsed time between location updates will never be less than
-     * minTime, although it can be more depending on the Location Provider
-     * implementation and the update interval requested by other applications.
-     *
-     * <p> Choosing a sensible value for minTime is important to conserve
-     * battery life. Each location update requires power from
-     * GPS, WIFI, Cell and other radios. Select a minTime value as high as
-     * possible while still providing a reasonable user experience.
-     * If your application is not in the foreground and showing
-     * location to the user then your application should avoid using an active
-     * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
-     * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
-     * or greater. If your application is in the foreground and showing
-     * location to the user then it is appropriate to select a faster
-     * update interval.
-     *
-     * <p> The minDistance parameter can also be used to control the
-     * frequency of location updates. If it is greater than 0 then the
-     * location provider will only send your application an update when
-     * the location has changed by at least minDistance meters, AND
-     * at least minTime milliseconds have passed. However it is more
-     * difficult for location providers to save power using the minDistance
-     * parameter, so minTime should be the primary tool to conserving battery
-     * life.
-     *
-     * <p> If your application wants to passively observe location
-     * updates triggered by other applications, but not consume
-     * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
-     * This provider does not actively turn on or modify active location
-     * providers, so you do not need to be as careful about minTime and
-     * minDistance. However if your application performs heavy work
-     * on a location update (such as network activity) then you should
-     * select non-zero values for minTime and/or minDistance to rate-limit
-     * your update frequency in the case another application enables a
-     * location provider with extremely fast updates.
-     *
-     * <p>In case the provider is disabled by the user, updates will stop,
-     * and a provider availability update will be sent.
-     * As soon as the provider is enabled again,
-     * location updates will immediately resume and a provider availability
-     * update sent. Providers can also send status updates, at any time,
-     * with extra's specific to the provider. If a callback was supplied
-     * then status and availability updates are via
-     * {@link LocationListener#onProviderDisabled},
-     * {@link LocationListener#onProviderEnabled} or
-     * {@link LocationListener#onStatusChanged}. Alternately, if a
-     * pending intent was supplied then status and availability updates
-     * are broadcast intents with extra keys of
-     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.
-     *
-     * <p> If a {@link LocationListener} is used but with no Looper specified
-     * then the calling thread must already
-     * be a {@link android.os.Looper} thread such as the main thread of the
-     * calling Activity. If a Looper is specified with a {@link LocationListener}
-     * then callbacks are made on the supplied Looper thread.
-     *
-     * <p> When location callbacks are invoked, the system will hold a wakelock
-     * on your application's behalf for some period of time, but not
-     * indefinitely. If your application requires a long running wakelock
-     * within the location callback, you should acquire it yourself.
-     *
-     * <p class="note"> Prior to Jellybean, the minTime parameter was
-     * only a hint, and some location provider implementations ignored it.
-     * From Jellybean and onwards it is mandatory for Android compatible
-     * devices to observe both the minTime and minDistance parameters.
-     *
-     * @param minTime minimum time interval between location updates, in milliseconds
-     * @param minDistance minimum distance between location updates, in meters
-     * @param criteria contains parameters for the location manager to choose the
-     * appropriate provider and parameters to compute the location
-     * @param intent a {@link PendingIntent} to be sent for each location update
-     *
-     * @throws IllegalArgumentException if criteria is null
-     * @throws IllegalArgumentException if intent is null
+     * @throws IllegalArgumentException if provider is null or doesn't exist
+     * @throws IllegalArgumentException if pendingIntent is null
      * @throws SecurityException if no suitable permission is present
      */
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(long minTime, float minDistance, @NonNull Criteria criteria,
-            @NonNull PendingIntent intent) {
-        checkCriteria(criteria);
-        checkPendingIntent(intent);
+    public void requestLocationUpdates(long minTimeMs, float minDistanceM,
+            @NonNull Criteria criteria, @NonNull PendingIntent pendingIntent) {
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+        checkPendingIntent(pendingIntent);
 
         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
-                criteria, minTime, minDistance, false);
-        requestLocationUpdates(request, intent);
+                criteria, minTimeMs, minDistanceM, false);
+        requestLocationUpdates(request, pendingIntent);
     }
 
     /**
-     * Register for fused location updates using a LocationRequest and callback.
+     * Register for location updates using a {@link LocationRequest}, and a callback on the
+     * specified {@link Looper}.
      *
-     * <p>Upon a location update, the system delivers the new {@link Location} to the
-     * provided {@link LocationListener}, by calling its {@link
-     * LocationListener#onLocationChanged} method.</p>
+     * <p>The system will automatically select and enable the best provider based on the given
+     * {@link LocationRequest}. The LocationRequest can be null, in which case the system will
+     * choose default low power parameters for location updates, but this is heavily discouraged,
+     * and an explicit LocationRequest should always be provided.
      *
-     * <p>The system will automatically select and enable the best providers
-     * to compute a location for your application. It may use only passive
-     * locations, or just a single location source, or it may fuse together
-     * multiple location sources in order to produce the best possible
-     * result, depending on the quality of service requested in the
-     * {@link LocationRequest}.
+     * <p>See {@link #requestLocationUpdates(String, long, float, LocationListener)}
+     * for more detail on how this method works.
      *
-     * <p>LocationRequest can be null, in which case the system will choose
-     * default, low power parameters for location updates. You will occasionally
-     * receive location updates as available, without a major power impact on the
-     * system. If your application just needs an occasional location update
-     * without any strict demands, then pass a null LocationRequest.
-     *
-     * <p>Only one LocationRequest can be registered for each unique callback
-     * or pending intent. So a subsequent request with the same callback or
-     * pending intent will over-write the previous LocationRequest.
-     *
-     * <p> If a pending intent is supplied then location updates
-     * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
-     * {@link android.location.Location} value. If a callback is supplied
-     * then location updates are made using the
-     * {@link LocationListener#onLocationChanged} callback, on the specified
-     * Looper thread. If a {@link LocationListener} is used
-     * but with a null Looper then the calling thread must already
-     * be a {@link android.os.Looper} thread (such as the main thread) and
-     * callbacks will occur on this thread.
-     *
-     * <p> Provider status updates and availability updates are deprecated
-     * because the system is performing provider fusion on the applications
-     * behalf. So {@link LocationListener#onProviderDisabled},
-     * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}
-     * will not be called, and intents with extra keys of
-     * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not
-     * be received.
-     *
-     * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}.
-     *
-     * @param locationRequest quality of service required, null for default low power
-     * @param listener a {@link LocationListener} whose
-     * {@link LocationListener#onLocationChanged} method will be called when
-     * the location update is available
-     * @param looper a Looper object whose message queue will be used to
-     * implement the callback mechanism, or null to make callbacks on the calling
-     * thread
+     * @param locationRequest the location request containing location parameters
+     * @param listener the listener to receive location updates
+     * @param looper the looper handling listener callbacks, or null to use the looper of the
+     *               calling thread
      *
      * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
@@ -1007,7 +937,7 @@
     @TestApi
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestLocationUpdates(
-            @NonNull LocationRequest locationRequest,
+            @Nullable LocationRequest locationRequest,
             @NonNull LocationListener listener,
             @Nullable Looper looper) {
         requestLocationUpdates(locationRequest,
@@ -1016,45 +946,18 @@
     }
 
     /**
-     * Register for location updates with the given {@link LocationRequest}.
+     * Register for location updates using a {@link LocationRequest}, and a callback on the
+     * specified {@link Executor}.
      *
-     * <p>See {@link #requestLocationUpdates(String, long, float, Executor, LocationListener)} for
-     * more information.
+     * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} for more
+     * detail on how this method works.
      *
-     * @param locationRequest the {@link LocationRequest} being made
-     * @param executor        all listener updates will take place on this {@link Executor}
-     * @param listener        a {@link LocationListener} that will be called when updates are
-     *                        available
-     * @throws IllegalArgumentException if locationRequest, listener, or executor is null
-     * @throws SecurityException        if no suitable permission is present
-     * @hide
-     */
-    @SystemApi
-    @TestApi
-    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
-    public void requestLocationUpdates(
-            @NonNull LocationRequest locationRequest,
-            @NonNull @CallbackExecutor Executor executor,
-            @NonNull LocationListener listener) {
-        requestLocationUpdates(locationRequest, new LocationListenerTransport(executor, listener));
-    }
-
-    /**
-     * Register for fused location updates using a LocationRequest and a pending intent.
+     * @param locationRequest the location request containing location parameters
+     * @param executor the executor handling listener callbacks
+     * @param listener the listener to receive location updates
      *
-     * <p>Upon a location update, the system delivers the new {@link Location} with your provided
-     * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
-     * in the intent's extras.</p>
-     *
-     * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
-     *
-     * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
-     * for more detail.
-     *
-     * @param locationRequest quality of service required, null for default low power
-     * @param pendingIntent a {@link PendingIntent} to be sent for the location update
-     *
-     * @throws IllegalArgumentException if intent is null
+     * @throws IllegalArgumentException if executor is null
+     * @throws IllegalArgumentException if listener is null
      * @throws SecurityException if no suitable permission is present
      *
      * @hide
@@ -1063,7 +966,33 @@
     @TestApi
     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
     public void requestLocationUpdates(
-            @NonNull LocationRequest locationRequest,
+            @Nullable LocationRequest locationRequest,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull LocationListener listener) {
+        requestLocationUpdates(locationRequest, new LocationListenerTransport(executor, listener));
+    }
+
+    /**
+     * Register for location updates using a {@link LocationRequest}, and callbacks delivered via
+     * the provided {@link PendingIntent}.
+     *
+     * <p>See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)} and
+     * {@link #requestLocationUpdates(String, long, float, PendingIntent)} for more detail on how
+     * this method works.
+     *
+     * @param locationRequest the location request containing location parameters
+     * @param pendingIntent the pending intent to send location updates
+     *
+     * @throws IllegalArgumentException if pendingIntent is null
+     * @throws SecurityException if no suitable permission is present
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
+    public void requestLocationUpdates(
+            @Nullable LocationRequest locationRequest,
             @NonNull PendingIntent pendingIntent) {
         Preconditions.checkArgument(locationRequest != null, "invalid null location request");
         Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
@@ -1080,8 +1009,8 @@
         }
     }
 
-    private void requestLocationUpdates(LocationRequest request,
-            LocationListenerTransport transport) {
+    private void requestLocationUpdates(@Nullable LocationRequest request,
+            @NonNull LocationListenerTransport transport) {
         synchronized (mListeners) {
             LocationListenerTransport oldTransport = mListeners.put(transport.getKey(), transport);
             if (oldTransport != null) {
@@ -1105,31 +1034,41 @@
      * chipset is in the process of getting the first fix.  If the client has cached the location,
      * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link
      * #getLastKnownLocation(String)}, the location information is still useful before getting
-     * the first fix.</p>
+     * the first fix.
      *
-     * <p> Useful in products like Auto.
+     * @param location newly available {@link Location} object
+     * @return true if the location was successfully injected, false otherwise
      *
-     * @param newLocation newly available {@link Location} object
-     * @return true if update was successful, false if not
-     *
-     * @throws SecurityException if no suitable permission is present
+     * @throws IllegalArgumentException if location is null
+     * @throws SecurityException if permissions are not present
      *
      * @hide
      */
     @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION})
-    public boolean injectLocation(@NonNull Location newLocation) {
+    public boolean injectLocation(@NonNull Location location) {
+        if (location == null) {
+            IllegalArgumentException e = new IllegalArgumentException("invalid null location");
+            if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+                throw e;
+            } else {
+                Log.w(TAG, e);
+                return false;
+            }
+        }
+
         try {
-            return mService.injectLocation(newLocation);
+            return mService.injectLocation(location);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Removes location updates for the specified LocationListener. Following this call, updates
-     * will no longer occur for this listener.
+     * Removes location updates for the specified {@link LocationListener}. Following this call,
+     * the listener will no longer receive location updates.
      *
      * @param listener listener that no longer needs location updates
+     *
      * @throws IllegalArgumentException if listener is null
      */
     public void removeUpdates(@NonNull LocationListener listener) {
@@ -1151,10 +1090,11 @@
     }
 
     /**
-     * Removes all location updates for the specified pending intent. Following this call, updates
-     * will no longer occur for this pending intent.
+     * Removes location updates for the specified {@link PendingIntent}. Following this call, the
+     * PendingIntent will no longer receive location updates.
      *
      * @param pendingIntent pending intent that no longer needs location updates
+     *
      * @throws IllegalArgumentException if pendingIntent is null
      */
     public void removeUpdates(@NonNull PendingIntent pendingIntent) {
@@ -1168,11 +1108,11 @@
     }
 
     /**
-     * Returns a list of the names of all known location providers.
-     * <p>All providers are returned, including ones that are not permitted to
-     * be accessed by the calling activity or are currently disabled.
+     * Returns a list of the names of all known location providers. All providers are returned,
+     * including ones that are not permitted to be accessed by the calling activity or are currently
+     * disabled.
      *
-     * @return list of Strings containing names of the provider
+     * @return list of provider names
      */
     public @NonNull List<String> getAllProviders() {
         try {
@@ -1183,11 +1123,11 @@
     }
 
     /**
-     * Returns a list of the names of location providers.
+     * Returns a list of the names of location providers. Only providers that the caller has
+     * permission to access will be returned.
      *
-     * @param enabledOnly if true then only the providers which are currently
-     * enabled are returned.
-     * @return list of Strings containing names of the providers
+     * @param enabledOnly if true then only enabled providers are included
+     * @return list of provider names
      */
     public @NonNull List<String> getProviders(boolean enabledOnly) {
         try {
@@ -1198,17 +1138,18 @@
     }
 
     /**
-     * Returns a list of the names of LocationProviders that satisfy the given
-     * criteria, or null if none do.  Only providers that are permitted to be
-     * accessed by the calling activity will be returned.
+     * Returns a list of the names of providers that satisfy the given criteria. Only providers that
+     * the caller has permission to access will be returned.
      *
-     * @param criteria the criteria that the returned providers must match
-     * @param enabledOnly if true then only the providers which are currently
-     * enabled are returned.
-     * @return list of Strings containing names of the providers
+     * @param criteria the criteria that providers must match
+     * @param enabledOnly if true then only enabled providers are included
+     * @return list of provider names
+     *
+     * @throws IllegalArgumentException if criteria is null
      */
     public @NonNull List<String> getProviders(@NonNull Criteria criteria, boolean enabledOnly) {
-        checkCriteria(criteria);
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+
         try {
             return mService.getProviders(criteria, enabledOnly);
         } catch (RemoteException e) {
@@ -1217,11 +1158,10 @@
     }
 
     /**
-     * Returns the name of the provider that best meets the given criteria. Only providers
-     * that are permitted to be accessed by the calling activity will be
-     * returned.  If several providers meet the criteria, the one with the best
-     * accuracy is returned.  If no provider meets the criteria,
-     * the criteria are loosened in the following sequence:
+     * Returns the name of the provider that best meets the given criteria. Only providers that are
+     * permitted to be accessed by the caller will be returned. If several providers meet the
+     * criteria, the one with the best accuracy is returned. If no provider meets the criteria, the
+     * criteria are loosened in the following order:
      *
      * <ul>
      * <li> power requirement
@@ -1231,15 +1171,17 @@
      * <li> altitude
      * </ul>
      *
-     * <p> Note that the requirement on monetary cost is not removed
-     * in this process.
+     * <p> Note that the requirement on monetary cost is not removed in this process.
      *
      * @param criteria the criteria that need to be matched
-     * @param enabledOnly if true then only a provider that is currently enabled is returned
-     * @return name of the provider that best matches the requirements
+     * @param enabledOnly if true then only enabled providers are included
+     * @return name of the provider that best matches the criteria, or null if none match
+     *
+     * @throws IllegalArgumentException if criteria is null
      */
     public @Nullable String getBestProvider(@NonNull Criteria criteria, boolean enabledOnly) {
-        checkCriteria(criteria);
+        Preconditions.checkArgument(criteria != null, "invalid null criteria");
+
         try {
             return mService.getBestProvider(criteria, enabledOnly);
         } catch (RemoteException e) {
@@ -1248,24 +1190,22 @@
     }
 
     /**
-     * Returns the information associated with the location provider of the
-     * given name, or null if no provider exists by that name.
+     * Returns the information about the location provider with the given name, or null if no
+     * provider exists by that name.
      *
-     * @param name the provider name
-     * @return a LocationProvider, or null
+     * @param provider the provider name
+     * @return location provider information, or null if provider does not exist
      *
-     * @throws IllegalArgumentException if name is null or does not exist
-     * @throws SecurityException if the caller is not permitted to access the
-     * given provider.
+     * @throws IllegalArgumentException if provider is null
      */
-    public @Nullable LocationProvider getProvider(@NonNull String name) {
-        checkProvider(name);
+    public @Nullable LocationProvider getProvider(@NonNull String provider) {
+        Preconditions.checkArgument(provider != null, "invalid null provider");
         try {
-            ProviderProperties properties = mService.getProviderProperties(name);
+            ProviderProperties properties = mService.getProviderProperties(provider);
             if (properties == null) {
                 return null;
             }
-            return new LocationProvider(name, properties);
+            return new LocationProvider(provider, properties);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1292,10 +1232,10 @@
      * Sends additional commands to a location provider. Can be used to support provider specific
      * extensions to the Location Manager API.
      *
-     * @param provider name of the location provider.
-     * @param command  name of the command to send to the provider.
-     * @param extras   optional arguments for the command (or null).
-     * @return true always
+     * @param provider name of the location provider
+     * @param command  name of the command to send to the provider
+     * @param extras   optional arguments for the command, or null
+     * @return true always, the return value may be ignored
      */
     public boolean sendExtraCommand(
             @NonNull String provider, @NonNull String command, @Nullable Bundle extras) {
@@ -1469,7 +1409,7 @@
     @TestApi
     @NonNull
     public List<LocationRequest> getTestProviderCurrentRequests(String providerName) {
-        checkProvider(providerName);
+        Preconditions.checkArgument(providerName != null, "invalid null provider");
         try {
             return mService.getTestProviderCurrentRequests(providerName,
                     mContext.getOpPackageName());
@@ -1558,10 +1498,9 @@
      */
     public void removeProximityAlert(@NonNull PendingIntent intent) {
         checkPendingIntent(intent);
-        String packageName = mContext.getPackageName();
 
         try {
-            mService.removeGeofence(null, intent, packageName);
+            mService.removeGeofence(null, intent, mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1609,7 +1548,7 @@
             @NonNull Geofence fence,
             @NonNull PendingIntent intent) {
         checkPendingIntent(intent);
-        checkGeofence(fence);
+        Preconditions.checkArgument(fence != null, "invalid null geofence");
 
         try {
             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
@@ -1636,11 +1575,10 @@
      */
     public void removeGeofence(@NonNull Geofence fence, @NonNull PendingIntent intent) {
         checkPendingIntent(intent);
-        checkGeofence(fence);
-        String packageName = mContext.getPackageName();
+        Preconditions.checkArgument(fence != null, "invalid null geofence");
 
         try {
-            mService.removeGeofence(fence, intent, packageName);
+            mService.removeGeofence(fence, intent, mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1659,10 +1597,9 @@
      */
     public void removeAllGeofences(@NonNull PendingIntent intent) {
         checkPendingIntent(intent);
-        String packageName = mContext.getPackageName();
 
         try {
-            mService.removeGeofence(null, intent, packageName);
+            mService.removeGeofence(null, intent, mContext.getPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1723,15 +1660,16 @@
     }
 
     /**
-     * Retrieves information about the current status of the GPS engine.
-     * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
-     * callback to ensure that the data is copied atomically.
+     * Retrieves information about the current status of the GPS engine. This should only be called
+     * from within the {@link GpsStatus.Listener#onGpsStatusChanged} callback to ensure that the
+     * data is copied atomically.
      *
-     * The caller may either pass in a {@link GpsStatus} object to set with the latest
-     * status information, or pass null to create a new {@link GpsStatus} object.
+     * The caller may either pass in an existing {@link GpsStatus} object to be overwritten, or pass
+     * null to create a new {@link GpsStatus} object.
      *
      * @param status object containing GPS status details, or null.
      * @return status object containing updated GPS status.
+     *
      * @deprecated GpsStatus APIs are deprecated, use {@link GnssStatus} APIs instead.
      */
     @Deprecated
@@ -1756,12 +1694,21 @@
      * @param listener GPS status listener object to register
      * @return true if the listener was successfully added
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     *
      * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead. No longer
      * supported in apps targeting R and above.
      */
     @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
+        UnsupportedOperationException ex = new UnsupportedOperationException(
+                "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
+        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+            throw ex;
+        } else {
+            Log.w(TAG, ex);
+        }
+
         try {
             return mGnssStatusListenerManager.addListener(listener, new Handler());
         } catch (RemoteException e) {
@@ -1773,11 +1720,20 @@
      * Removes a GPS status listener.
      *
      * @param listener GPS status listener object to remove
+     *
      * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead. No longer
      * supported in apps targeting R and above.
      */
     @Deprecated
     public void removeGpsStatusListener(GpsStatus.Listener listener) {
+        UnsupportedOperationException ex = new UnsupportedOperationException(
+                "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
+        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+            throw ex;
+        } else {
+            Log.w(TAG, ex);
+        }
+
         try {
             mGnssStatusListenerManager.removeListener(listener);
         } catch (RemoteException e) {
@@ -1790,7 +1746,9 @@
      *
      * @param callback GNSS status callback object to register
      * @return true if the listener was successfully added
+     *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     *
      * @deprecated Use {@link #registerGnssStatusCallback(GnssStatus.Callback, Handler)} or {@link
      * #registerGnssStatusCallback(Executor, GnssStatus.Callback)} instead.
      */
@@ -1804,8 +1762,9 @@
      * Registers a GNSS status callback.
      *
      * @param callback GNSS status callback object to register
-     * @param handler  a handler with a looper that the callback runs on.
+     * @param handler  a handler with a looper that the callback runs on
      * @return true if the listener was successfully added
+     *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
@@ -1826,8 +1785,9 @@
      * Registers a GNSS status callback.
      *
      * @param callback GNSS status callback object to register
-     * @param executor the executor that the callback runs on.
+     * @param executor the executor that the callback runs on
      * @return true if the listener was successfully added
+     *
      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
@@ -1855,13 +1815,8 @@
     }
 
     /**
-     * Adds an NMEA listener.
+     * No-op method to keep backward-compatibility.
      *
-     * @param listener a {@link GpsStatus.NmeaListener} object to register
-     *
-     * @return true if the listener was successfully added
-     *
-     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
      * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead.
      * @removed
      */
@@ -1872,9 +1827,8 @@
     }
 
     /**
-     * Removes an NMEA listener.
+     * No-op method to keep backward-compatibility.
      *
-     * @param listener a {@link GpsStatus.NmeaListener} object to remove
      * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
      * @removed
      */
@@ -1951,30 +1905,26 @@
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
+     *
      * @hide
-     * @deprecated Not supported anymore.
+     * @deprecated Use {@link #registerGnssMeasurementsCallback} instead.
      * @removed
      */
     @Deprecated
     @SystemApi
-    @SuppressLint("Doclava125")
     public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
         return false;
     }
 
     /**
-     * No-op method to keep backward-compatibility. Don't use it. Use {@link
-     * #unregisterGnssMeasurementsCallback} instead.
+     * No-op method to keep backward-compatibility.
      *
      * @hide
-     * @deprecated use {@link #unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback)}
-     *     instead.
+     * @deprecated Use {@link #unregisterGnssMeasurementsCallback} instead.
      * @removed
      */
     @Deprecated
     @SystemApi
-    @SuppressLint("Doclava125")
     public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {}
 
     /**
@@ -2067,30 +2017,26 @@
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead.
+     *
      * @hide
-     * @deprecated Not supported anymore.
+     * @deprecated Use {@link #registerGnssNavigationMessageCallback} instead.
      * @removed
      */
     @Deprecated
     @SystemApi
-    @SuppressLint("Doclava125")
     public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
         return false;
     }
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead.
+     *
      * @hide
-     * @deprecated use
-     * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)}
-     * instead
+     * @deprecated Use {@link #unregisterGnssNavigationMessageCallback} instead.
      * @removed
      */
     @Deprecated
     @SystemApi
-    @SuppressLint("Doclava125")
     public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {}
 
     /**
@@ -2276,31 +2222,11 @@
         }
     }
 
-    private static void checkProvider(String provider) {
-        if (provider == null) {
-            throw new IllegalArgumentException("invalid provider: " + provider);
-        }
-    }
-
-    private static void checkCriteria(Criteria criteria) {
-        if (criteria == null) {
-            throw new IllegalArgumentException("invalid criteria: " + criteria);
-        }
-    }
-
-    private static void checkListener(LocationListener listener) {
-        if (listener == null) {
-            throw new IllegalArgumentException("invalid listener: " + listener);
-        }
-    }
-
-    private void checkPendingIntent(PendingIntent intent) {
-        if (intent == null) {
-            throw new IllegalArgumentException("invalid pending intent: " + intent);
-        }
-        if (!intent.isTargetedToPackage()) {
+    private void checkPendingIntent(PendingIntent pendingIntent) {
+        Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
+        if (!pendingIntent.isTargetedToPackage()) {
             IllegalArgumentException e = new IllegalArgumentException(
-                    "pending intent must be targeted to package");
+                    "invalid pending intent - must be targeted to package");
             if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
                 throw e;
             } else {
@@ -2309,12 +2235,6 @@
         }
     }
 
-    private static void checkGeofence(Geofence fence) {
-        if (fence == null) {
-            throw new IllegalArgumentException("invalid geofence: " + fence);
-        }
-    }
-
     private class LocationListenerTransport extends ILocationListener.Stub {
 
         private final Executor mExecutor;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 2d6cd24..f797da7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1857,12 +1857,37 @@
     }
 
     /**
+     * @hide
+     * Sets the microphone from switch mute on or off.
+     * <p>
+     * This method should only be used by InputManager to notify
+     * Audio Subsystem about Microphone Mute switch state.
+     *
+     * @param on set <var>true</var> to mute the microphone;
+     *           <var>false</var> to turn mute off
+     */
+    @UnsupportedAppUsage
+    public void setMicrophoneMuteFromSwitch(boolean on) {
+        final IAudioService service = getService();
+        try {
+            service.setMicrophoneMuteFromSwitch(on);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks whether the microphone mute is on or off.
      *
      * @return true if microphone is muted, false if it's not
      */
     public boolean isMicrophoneMute() {
-        return AudioSystem.isMicrophoneMuted();
+        final IAudioService service = getService();
+        try {
+            return service.isMicrophoneMuted();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 71f52a1..fc05610 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -106,8 +106,12 @@
 
     List<AudioProductStrategy> getAudioProductStrategies();
 
+    boolean isMicrophoneMuted();
+
     void setMicrophoneMute(boolean on, String callingPackage, int userId);
 
+    oneway void setMicrophoneMuteFromSwitch(boolean on);
+
     void setRingerModeExternal(int ringerMode, String caller);
 
     void setRingerModeInternal(int ringerMode, String caller);
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 378064d..45ee210 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -34,6 +34,7 @@
         "libutils",
         "libbinder",
         "libmedia",
+        "libmedia_codeclist",
         "libmedia_jni_utils",
         "libmedia_omx",
         "libmediametrics",
@@ -58,7 +59,10 @@
         "android.hidl.token@1.0-utils",
     ],
 
-    header_libs: ["libhardware_headers"],
+    header_libs: [
+        "libhardware_headers",
+        "libmediadrm_headers",
+    ],
 
     static_libs: ["libgrallocusage"],
 
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 5ebac1d..684069b 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -20,15 +20,12 @@
 #include "jni.h"
 
 #include <media/stagefright/foundation/ABase.h>
-#include <media/IDrm.h>
-#include <media/IDrmClient.h>
+#include <mediadrm/IDrm.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
 namespace android {
 
-struct IDrm;
-
 class DrmListener: virtual public RefBase
 {
 public:
diff --git a/mime/Android.bp b/mime/Android.bp
new file mode 100644
index 0000000..8b2b059
--- /dev/null
+++ b/mime/Android.bp
@@ -0,0 +1,114 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+java_defaults {
+    name: "mimemap-defaults",
+    srcs: [
+        "java/android/content/type/DefaultMimeMapFactory.java",
+    ],
+    sdk_version: "core_platform",
+}
+
+java_library {
+    name: "mimemap",
+    defaults: ["mimemap-defaults"],
+    static_libs: ["mimemap-res.jar"],
+    visibility: [
+        "//frameworks/base:__subpackages__",
+    ],
+}
+
+java_library {
+    name: "mimemap-testing",
+    defaults: ["mimemap-defaults"],
+    static_libs: ["mimemap-testing-res.jar"],
+    jarjar_rules: "jarjar-rules.txt",
+    visibility: [
+        "//cts/tests/tests/mimemap:__subpackages__",
+        "//frameworks/base:__subpackages__",
+    ],
+}
+
+// The mimemap-res.jar and mimemap-testing-res.jar genrules produce a .jar that
+// has the resource file in a subdirectory res/ and testres/, respectively.
+// They need to be in different paths because one of them ends up in a
+// bootclasspath jar whereas the other one ends up in a test jar. Bootclasspath
+// resources hide test or application resources under the same path because
+// ClassLoader.getResource(String) consults the parent ClassLoader first.
+//
+// Further notes:
+//  - the "cp" command will flatten any directory paths that occur in $(in),
+//    but here they happen to already be in the root directory. If we needed
+//    to preserve sub paths then we might want to zip the files first and then
+//    unzip them below the new parent directory.
+//  - the path names "res/" and "testres/" and duplicated in .java source files
+//    (DefaultMimeMapFactory.java and MimeMapTest.java, as of October 2019).
+java_genrule {
+    name: "mimemap-res.jar",
+    tools: [
+        "soong_zip",
+    ],
+    srcs: [":mime.types"],
+    out: ["mimemap-res.jar"],
+    cmd: "mkdir $(genDir)/res/ && cp $(in) $(genDir)/res/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/res/",
+}
+
+// The same as mimemap-res.jar except that the resources are placed in a different directory.
+// They get bundled with CTS so that CTS can compare a device's MimeMap implementation vs.
+// the stock Android one from when CTS was built.
+java_genrule {
+    name: "mimemap-testing-res.jar",
+    tools: [
+        "soong_zip",
+    ],
+    srcs: [":mime.types"],
+    out: ["mimemap-testing-res.jar"],
+    cmd: "mkdir $(genDir)/testres/ && cp $(in) $(genDir)/testres/ && $(location soong_zip) -C $(genDir) -o $(out) -D $(genDir)/testres/",
+}
+
+// Combination of all *mime.types resources.
+filegroup {
+    name: "mime.types",
+    visibility: [
+        "//visibility:private",
+    ],
+    srcs: [
+        ":debian.mime.types",
+        ":android.mime.types",
+        ":vendor.mime.types",
+    ],
+}
+
+filegroup {
+    name: "android.mime.types",
+    visibility: [
+        "//visibility:private",
+    ],
+    path: "java-res/",
+    srcs: [
+        "java-res/android.mime.types",
+    ],
+}
+
+filegroup {
+    name: "vendor.mime.types",
+    visibility: [
+        "//visibility:private",
+    ],
+    path: "java-res/",
+    srcs: [
+        "java-res/vendor.mime.types",
+    ],
+}
diff --git a/mime/TEST_MAPPING b/mime/TEST_MAPPING
new file mode 100644
index 0000000..8daab75
--- /dev/null
+++ b/mime/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsMimeMapTestCases"
+    }
+  ]
+}
diff --git a/mime/jarjar-rules.txt b/mime/jarjar-rules.txt
new file mode 100644
index 0000000..145d1db
--- /dev/null
+++ b/mime/jarjar-rules.txt
@@ -0,0 +1 @@
+rule android.content.type.DefaultMimeMapFactory android.content.type.cts.StockAndroidMimeMapFactory
\ No newline at end of file
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
new file mode 100644
index 0000000..7a5299f
--- /dev/null
+++ b/mime/java-res/android.mime.types
@@ -0,0 +1,146 @@
+
+###############################################################################
+#
+# Android-specific MIME type <-> extension mappings
+#
+# Each line below defines a mapping from one MIME type to the first of the
+# listed extensions, and from listed extension back to the MIME type.
+# A mapping overrides any previous mapping _from_ that same MIME type or
+# extension (put() semantics), unless that MIME type / extension is prefixed with '?'
+# (putIfAbsent() semantics).
+#
+#
+###############################################################################
+#
+# EXAMPLES
+#
+# A line of the form:
+#
+#    ?mime ext1 ?ext2 ext3
+#
+# affects the current mappings along the lines of the following pseudo code:
+#
+#    mimeToExt.putIfAbsent("mime", "ext1");
+#    extToMime.put("ext1", "mime");
+#    extToMime.putIfAbsent("ext2", "mime");
+#    extToMime.put("ext3", "mime");
+#
+# The line:
+#
+#     ?text/plain txt
+#
+# leaves any earlier mapping for "text/plain" untouched, or maps that MIME type
+# to the file extension ".txt" if there is no earlier mapping. The line also
+# sets the mapping from file extension ".txt" to be the MIME type "text/plain",
+# regardless of whether a previous mapping existed.
+#
+###############################################################################
+
+
+# File extensions that Android wants to override to point to the given MIME type.
+#
+# After processing a line of the form:
+# ?<mimeType> <extension1> <extension2>
+# If <mimeType> was not already mapped to an extension then it will be
+# mapped to <extension1>.
+# <extension1> and <extension2> are mapped (or remapped) to <mimeType>.
+
+?application/epub+zip epub
+?application/pkix-cert cer
+?application/rss+xml rss
+?application/vnd.android.ota ota
+?application/vnd.apple.mpegurl m3u8
+?application/vnd.ms-pki.stl stl
+?application/vnd.ms-powerpoint pot
+?application/vnd.ms-wpl wpl
+?application/vnd.stardivision.impress sdp
+?application/vnd.stardivision.writer vor
+?application/vnd.youtube.yt yt
+?application/x-android-drm-fl fl
+?application/x-flac flac
+?application/x-font pcf
+?application/x-mpegurl m3u m3u8
+?application/x-pem-file pem
+?application/x-pkcs12 p12 pfx
+?application/x-webarchive webarchive
+?application/x-webarchive-xml webarchivexml
+?application/x-x509-server-cert crt
+?application/x-x509-user-cert crt
+
+?audio/3gpp 3gpp
+?audio/aac-adts aac
+?audio/imelody imy
+?audio/midi rtttl xmf
+?audio/mobile-xmf mxmf
+?audio/mp4 m4a
+?audio/mpegurl m3u
+?audio/sp-midi smf
+?audio/x-matroska mka
+?audio/x-pn-realaudio ra
+
+?image/bmp bmp
+?image/heic heic
+?image/heic-sequence heics
+?image/heif heif hif
+?image/heif-sequence heifs
+?image/ico cur
+?image/webp webp
+?image/x-adobe-dng dng
+?image/x-fuji-raf raf
+?image/x-icon ico
+?image/x-nikon-nrw nrw
+?image/x-panasonic-rw2 rw2
+?image/x-pentax-pef pef
+?image/x-samsung-srw srw
+?image/x-sony-arw arw
+
+?text/comma-separated-values csv
+?text/plain diff po
+?text/rtf rtf
+?text/text phps
+?text/xml xml
+?text/x-vcard vcf
+
+?video/3gpp2 3gpp2 3g2
+?video/3gpp 3gpp
+?video/avi avi
+?video/m4v m4v
+?video/mp2p mpeg
+?video/mp2t m2ts mts
+?video/mp2ts ts
+?video/vnd.youtube.yt yt
+?video/x-webex wrf
+
+# Optional additions that should not override any previous mapping.
+
+?application/x-wifi-config ?xml
+
+# Special cases where Android has a strong opinion about mappings, so we
+# define them very last and make them override in both directions (no "?").
+#
+# Lines here are of the form:
+# <mimeType> <extension1> <extension2> ...
+#
+# After processing each line,
+#   <mimeType> is mapped to <extension1>
+#   <extension1>, <extension2>, ... are all mapped to <mimeType>
+# This overrides any mappings for this <mimeType> / for these extensions
+# that may have been defined earlier.
+
+application/pgp-signature pgp
+application/x-x509-ca-cert crt
+audio/aac aac
+audio/basic snd
+audio/flac flac
+audio/midi rtx
+audio/mpeg mp3 m4a m4r
+audio/x-mpegurl m3u m3u8
+image/jpeg jpg
+image/x-ms-bmp bmp
+text/plain txt
+text/x-c++hdr hpp
+text/x-c++src cpp
+video/3gpp 3gpp
+video/mpeg mpeg
+video/quicktime mov
+video/x-matroska mkv
diff --git a/mime/java-res/vendor.mime.types b/mime/java-res/vendor.mime.types
new file mode 100644
index 0000000..afb8f9e
--- /dev/null
+++ b/mime/java-res/vendor.mime.types
@@ -0,0 +1,41 @@
+###############################################################################
+#
+# Vendor-specific MIME type <-> extension mappings
+#
+# Each line below defines a mapping from one MIME type to the first of the
+# listed extensions, and from listed extension back to the MIME type.
+#
+# This file can _add_ additional mappings that are not in the default set,
+# but it it cannot _modify_ (replace or remove) any platform default mapping
+# (defined in files mime.types and android.mime.types).
+#
+###############################################################################
+#
+# EXAMPLES
+#
+# A line of the form (without the leading '#''):
+#
+#    mime ext1 ext2 ext3
+#
+# affects the current mappings along the lines of the following pseudo code:
+#
+#    mimeToExt.putIfAbsent("mime", "ext1");
+#    extToMime.putIfAbsent("ext1", "mime");
+#    extToMime.putIfAbsent("ext2", "mime");
+#    extToMime.putIfAbsent("ext3", "mime");
+#
+# Optionally, MIME types or extensions may be prefixed by a single '?', which
+# will be ignored. I.e., the following example lines all have the same semantics:
+#
+#    mime ext1 ext2 ext3
+#    ?mime ext1 ext2 ext3
+#    mime ?ext1 ext2 ?ext3
+#    ?mime ?ext1 ?ext2 ?ext3
+#
+# By default, this file contains no mappings (which means that the platform
+# default mapping is used unmodified).
+#
+###############################################################################
+#
+# Add your custom mappings below this line (with no "#" at the start of the line):
+
diff --git a/mime/java/android/content/type/DefaultMimeMapFactory.java b/mime/java/android/content/type/DefaultMimeMapFactory.java
new file mode 100644
index 0000000..13039a4
--- /dev/null
+++ b/mime/java/android/content/type/DefaultMimeMapFactory.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.type;
+
+import libcore.net.MimeMap;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.regex.Pattern;
+
+/**
+ * Creates the framework default {@link MimeMap}, a bidirectional mapping
+ * between MIME types and file extensions.
+ *
+ * This default mapping is loaded from data files that start with some mappings
+ * recognized by IANA plus some custom extensions and overrides.
+ *
+ * @hide
+ */
+public class DefaultMimeMapFactory {
+
+    private DefaultMimeMapFactory() {
+    }
+
+    /**
+     * Creates and returns a new {@link MimeMap} instance that implements.
+     * Android's default mapping between MIME types and extensions.
+     */
+    public static MimeMap create() {
+        Class c = DefaultMimeMapFactory.class;
+        // The resources are placed into the res/ path by the "mimemap-res.jar" genrule.
+        return create(resourceName -> c.getResourceAsStream("/res/" + resourceName));
+    }
+
+    private static final Pattern SPLIT_PATTERN = Pattern.compile("\\s+");
+
+    /**
+     * Creates a {@link MimeMap} instance whose resources are loaded from the
+     * InputStreams looked up in {@code resourceSupplier}.
+     *
+     * @hide
+     */
+    public static MimeMap create(Function<String, InputStream> resourceSupplier) {
+        MimeMap.Builder builder = MimeMap.builder();
+        parseTypes(builder, true, resourceSupplier, "mime.types");
+        parseTypes(builder, true, resourceSupplier, "android.mime.types");
+        parseTypes(builder, false, resourceSupplier, "vendor.mime.types");
+        return builder.build();
+    }
+
+    private static void parseTypes(MimeMap.Builder builder, boolean allowOverwrite,
+            Function<String, InputStream> resourceSupplier, String resourceName) {
+        try (InputStream inputStream = Objects.requireNonNull(resourceSupplier.apply(resourceName));
+             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+            String line;
+            while ((line = reader.readLine()) != null) {
+                int commentPos = line.indexOf('#');
+                if (commentPos >= 0) {
+                    line = line.substring(0, commentPos);
+                }
+                line = line.trim();
+                if (line.isEmpty()) {
+                    continue;
+                }
+                List<String> specs = Arrays.asList(SPLIT_PATTERN.split(line));
+                if (!allowOverwrite) {
+                    // Pretend that the mimeType and each file extension listed in the line
+                    // carries a "?" prefix, which means that it can add new mappings but
+                    // not modify existing mappings (putIfAbsent() semantics).
+                    specs = ensurePrefix("?", specs);
+                }
+                builder.put(specs.get(0), specs.subList(1, specs.size()));
+            }
+        } catch (IOException | RuntimeException e) {
+            throw new RuntimeException("Failed to parse " + resourceName, e);
+        }
+    }
+
+    private static List<String> ensurePrefix(String prefix, List<String> strings) {
+        List<String> result = new ArrayList<>(strings.size());
+        for (String s : strings) {
+            if (!s.startsWith(prefix)) {
+                s = prefix + s;
+            }
+            result.add(s);
+        }
+        return result;
+    }
+
+}
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index ca8d5ac..cc46514 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -44,7 +44,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        int result = native_getInternalFormat(bitmap.getNativeInstance());
+        int result = native_getInternalFormat(bitmap);
         if (result < 0) {
             throw new IllegalArgumentException("Unknown internalformat");
         }
@@ -66,7 +66,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        int result = native_getType(bitmap.getNativeInstance());
+        int result = native_getType(bitmap);
         if (result < 0) {
             throw new IllegalArgumentException("Unknown type");
         }
@@ -103,8 +103,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), -1,
-                border) != 0) {
+        if (native_texImage2D(target, level, internalformat, bitmap, -1, border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -130,8 +129,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), type,
-              border) != 0) {
+        if (native_texImage2D(target, level, internalformat, bitmap, type, border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -153,7 +151,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, -1, bitmap.getNativeInstance(), -1, border) != 0) {
+        if (native_texImage2D(target, level, -1, bitmap, -1, border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -189,8 +187,7 @@
             throw new IllegalArgumentException("bitmap is recycled");
         }
         int type = getType(bitmap);
-        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(), -1,
-                type) != 0) {
+        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, -1, type) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -214,8 +211,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(),
-                format, type) != 0) {
+        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, format, type) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -265,10 +261,10 @@
         }
     }
 
-    native private static int native_getInternalFormat(long bitmapHandle);
-    native private static int native_getType(long bitmapHandle);
-    native private static int native_texImage2D(int target, int level, int internalformat,
-            long bitmapHandle, int type, int border);
-    native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset,
-            long bitmapHandle, int format, int type);
+    private static native int native_getInternalFormat(Bitmap bitmap);
+    private static native int native_getType(Bitmap bitmap);
+    private static native int native_texImage2D(int target, int level, int internalformat,
+            Bitmap bitmap, int type, int border);
+    private static native int native_texSubImage2D(int target, int level, int xoffset, int yoffset,
+            Bitmap bitmap, int format, int type);
 }
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java
new file mode 100644
index 0000000..f3ab2bde
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullBackupDataProcessor.java
@@ -0,0 +1,109 @@
+/*
+ * 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.encryption;
+
+import android.app.backup.BackupTransport;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/** Accepts the full backup data stream and sends it to the server. */
+public interface FullBackupDataProcessor {
+    /**
+     * Prepares the upload.
+     *
+     * <p>After this, call {@link #start()} to establish the connection.
+     *
+     * @param inputStream to read the backup data from, calling {@link #finish} or {@link #cancel}
+     *     will close the stream
+     * @return {@code true} if the connection was set up successfully, otherwise {@code false}
+     */
+    boolean initiate(InputStream inputStream) throws IOException;
+
+    /**
+     * Starts the upload, establishing the connection to the server.
+     *
+     * <p>After this, call {@link #pushData(int)} to request that the processor reads data from the
+     * socket, and uploads it to the server.
+     *
+     * <p>After this you must call one of {@link #cancel()}, {@link #finish()}, {@link
+     * #handleCheckSizeRejectionZeroBytes()}, {@link #handleCheckSizeRejectionQuotaExceeded()} or
+     * {@link #handleSendBytesQuotaExceeded()} to close the upload.
+     */
+    void start();
+
+    /**
+     * Requests that the processor read {@code numBytes} from the input stream passed in {@link
+     * #initiate(InputStream)} and upload them to the server.
+     *
+     * @return {@link BackupTransport#TRANSPORT_OK} if the upload succeeds, or {@link
+     *     BackupTransport#TRANSPORT_QUOTA_EXCEEDED} if the upload exceeded the server-side app size
+     *     quota, or {@link BackupTransport#TRANSPORT_PACKAGE_REJECTED} for other errors.
+     */
+    int pushData(int numBytes);
+
+    /** Cancels the upload and tears down the connection. */
+    void cancel();
+
+    /**
+     * Finish the upload and tear down the connection.
+     *
+     * <p>Call this after there is no more data to push with {@link #pushData(int)}.
+     *
+     * @return One of {@link BackupTransport#TRANSPORT_OK} if the app upload succeeds, {@link
+     *     BackupTransport#TRANSPORT_QUOTA_EXCEEDED} if the upload exceeded the server-side app size
+     *     quota, {@link BackupTransport#TRANSPORT_ERROR} for server 500s, or {@link
+     *     BackupTransport#TRANSPORT_PACKAGE_REJECTED} for other errors.
+     */
+    int finish();
+
+    /**
+     * Notifies the processor that the current upload should be terminated because the estimated
+     * size is zero.
+     */
+    void handleCheckSizeRejectionZeroBytes();
+
+    /**
+     * Notifies the processor that the current upload should be terminated because the estimated
+     * size exceeds the quota.
+     */
+    void handleCheckSizeRejectionQuotaExceeded();
+
+    /**
+     * Notifies this class that the current upload should be terminated because the quota was
+     * exceeded during upload.
+     */
+    void handleSendBytesQuotaExceeded();
+
+    /**
+     * Attaches {@link FullBackupCallbacks} which the processor will notify when the backup
+     * succeeds.
+     */
+    void attachCallbacks(FullBackupCallbacks fullBackupCallbacks);
+
+    /**
+     * Implemented by the caller of the processor to receive notification of when the backup
+     * succeeds.
+     */
+    interface FullBackupCallbacks {
+        /** The processor calls this to indicate that the current backup has succeeded. */
+        void onSuccess();
+
+        /** The processor calls this if the upload failed for a non-transient reason. */
+        void onTransferFailed();
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java
new file mode 100644
index 0000000..e4c4049
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDataProcessor.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import java.io.IOException;
+
+/**
+ * Retrieves the data during a full restore, decrypting it if necessary.
+ *
+ * <p>Use {@link FullRestoreDataProcessorFactory} to construct the encrypted or unencrypted
+ * processor as appropriate during restore.
+ */
+public interface FullRestoreDataProcessor {
+    /** Return value of {@link #readNextChunk} when there is no more data to download. */
+    int END_OF_STREAM = -1;
+
+    /**
+     * Reads the next chunk of restore data and writes it to the given buffer.
+     *
+     * <p>Where necessary, will open the connection to the server and/or decrypt the backup file.
+     *
+     * <p>The implementation may retry various errors. If the retries fail it will throw the
+     * relevant exception.
+     *
+     * @return the number of bytes read, or {@link #END_OF_STREAM} if there is no more data
+     * @throws IOException when downloading from the network or writing to disk
+     */
+    int readNextChunk(byte[] buffer) throws IOException;
+
+    /**
+     * Closes the connection to the server, deletes any temporary files and optionally sends a log
+     * with the given finish type.
+     *
+     * @param finishType one of {@link FullRestoreDownloader.FinishType}
+     */
+    void finish(FullRestoreDownloader.FinishType finishType);
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java
new file mode 100644
index 0000000..afcca79
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/FullRestoreDownloader.java
@@ -0,0 +1,47 @@
+/*
+ * 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.encryption;
+
+import java.io.IOException;
+
+/** Interface for classes which will provide backup data */
+public abstract class FullRestoreDownloader {
+    /** Enum to provide information on why a download finished */
+    public enum FinishType {
+        UNKNOWN_FINISH(0),
+        // Finish the downloading and successfully write data to Android OS.
+        FINISHED(1),
+        // Download failed with any kind of exception.
+        TRANSFER_FAILURE(2),
+        // Download failed due to auth failure on the device.
+        AUTH_FAILURE(3),
+        // Aborted by Android Framework.
+        FRAMEWORK_ABORTED(4);
+
+        private int mValue;
+
+        FinishType(int value) {
+            mValue = value;
+        }
+    }
+
+    /** Get the next data chunk from the backing store */
+    public abstract int readNextChunk(byte[] buffer) throws IOException;
+
+    /** Called when we've finished restoring the data */
+    public abstract void finish(FinishType finishType);
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
new file mode 100644
index 0000000..91b2926
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/StreamUtils.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/** Utility methods for dealing with Streams */
+public class StreamUtils {
+    /**
+     * Close a Closeable and silently ignore any IOExceptions.
+     *
+     * @param closeable The closeable to close
+     */
+    public static void closeQuietly(Closeable closeable) {
+        try {
+            closeable.close();
+        } catch (IOException ioe) {
+            // Silently ignore
+        }
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/client/UnexpectedActiveSecondaryOnServerException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/client/UnexpectedActiveSecondaryOnServerException.java
new file mode 100644
index 0000000..9e31385
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/client/UnexpectedActiveSecondaryOnServerException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.client;
+
+/**
+ * Error thrown when the user attempts to retrieve a key set from the server, but is asking for keys
+ * from an inactive secondary.
+ *
+ * <p>Although we could just return old keys, there is no good reason to do this. It almost
+ * certainly indicates a logic error on the client.
+ */
+public class UnexpectedActiveSecondaryOnServerException extends Exception {
+    public UnexpectedActiveSecondaryOnServerException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/ActiveSecondaryNotInKeychainException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/ActiveSecondaryNotInKeychainException.java
new file mode 100644
index 0000000..2e8a61f
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/ActiveSecondaryNotInKeychainException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.encryption.tasks;
+
+/**
+ * Error thrown when the server's active secondary key does not exist in the user's recoverable
+ * keychain. This means the backup data cannot be decrypted, and should be wiped.
+ */
+public class ActiveSecondaryNotInKeychainException extends Exception {
+    public ActiveSecondaryNotInKeychainException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java
new file mode 100644
index 0000000..9bf148d
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTask.java
@@ -0,0 +1,378 @@
+/*
+ * 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.encryption.tasks;
+
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkOrdering;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunksMetadata;
+
+import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Locale;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * A backup file consists of, in order:
+ *
+ * <ul>
+ *   <li>A randomly ordered sequence of encrypted chunks
+ *   <li>A plaintext {@link ChunksMetadata} proto, containing the bytes of an encrypted {@link
+ *       ChunkOrdering} proto.
+ *   <li>A 64-bit long denoting the offset of the file at which the ChunkOrdering proto starts.
+ * </ul>
+ *
+ * <p>This task decrypts such a blob and writes the plaintext to another file.
+ *
+ * <p>The backup file has two formats to indicate the boundaries of the chunks in the encrypted
+ * file. In {@link ChunksMetadataProto#EXPLICIT_STARTS} mode the chunk ordering contains the start
+ * positions of each chunk and the decryptor outputs the chunks in the order they appeared in the
+ * plaintext file. In {@link ChunksMetadataProto#INLINE_LENGTHS} mode the length of each encrypted
+ * chunk is prepended to the chunk in the file and the decryptor outputs the chunks in no specific
+ * order.
+ *
+ * <p>{@link ChunksMetadataProto#EXPLICIT_STARTS} is for use with full backup (Currently used for
+ * all backups as b/77188289 is not implemented yet), {@link ChunksMetadataProto#INLINE_LENGTHS}
+ * will be used for kv backup (once b/77188289 is implemented) to avoid re-uploading the chunk
+ * ordering (see b/70782620).
+ */
+public class BackupFileDecryptorTask {
+    private static final String TAG = "BackupFileDecryptorTask";
+
+    private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+    private static final int GCM_NONCE_LENGTH_BYTES = 12;
+    private static final int GCM_TAG_LENGTH_BYTES = 16;
+    private static final int BITS_PER_BYTE = 8;
+    private static final String READ_MODE = "r";
+    private static final int BYTES_PER_LONG = 64 / BITS_PER_BYTE;
+
+    private final Cipher mCipher;
+    private final SecretKey mSecretKey;
+
+    /**
+     * A new instance.
+     *
+     * @param secretKey The tertiary key used to encrypt the backup blob.
+     */
+    public BackupFileDecryptorTask(SecretKey secretKey)
+            throws NoSuchPaddingException, NoSuchAlgorithmException {
+        this.mCipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        this.mSecretKey = secretKey;
+    }
+
+    /**
+     * Runs the task, reading the encrypted data from {@code input} and writing the plaintext data
+     * to {@code output}.
+     *
+     * @param inputFile The encrypted backup file.
+     * @param decryptedChunkOutput Unopened output to write the plaintext to, which this class will
+     *     open and close during decryption.
+     * @throws IOException if an error occurred reading the encrypted file or writing the plaintext,
+     *     or if one of the protos could not be deserialized.
+     */
+    public void decryptFile(File inputFile, DecryptedChunkOutput decryptedChunkOutput)
+            throws IOException, EncryptedRestoreException, IllegalBlockSizeException,
+                    BadPaddingException, InvalidAlgorithmParameterException, InvalidKeyException,
+                    ShortBufferException, NoSuchAlgorithmException {
+        RandomAccessFile input = new RandomAccessFile(inputFile, READ_MODE);
+
+        long metadataOffset = getChunksMetadataOffset(input);
+        ChunksMetadataProto.ChunksMetadata chunksMetadata =
+                getChunksMetadata(input, metadataOffset);
+        ChunkOrdering chunkOrdering = decryptChunkOrdering(chunksMetadata);
+
+        if (chunksMetadata.chunkOrderingType == ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED
+                || chunksMetadata.chunkOrderingType == ChunksMetadataProto.EXPLICIT_STARTS) {
+            Slog.d(TAG, "Using explicit starts");
+            decryptFileWithExplicitStarts(
+                    input, decryptedChunkOutput, chunkOrdering, metadataOffset);
+
+        } else if (chunksMetadata.chunkOrderingType == ChunksMetadataProto.INLINE_LENGTHS) {
+            Slog.d(TAG, "Using inline lengths");
+            decryptFileWithInlineLengths(input, decryptedChunkOutput, metadataOffset);
+
+        } else {
+            throw new UnsupportedEncryptedFileException(
+                    "Unknown chunk ordering type:" + chunksMetadata.chunkOrderingType);
+        }
+
+        if (!Arrays.equals(decryptedChunkOutput.getDigest(), chunkOrdering.checksum)) {
+            throw new MessageDigestMismatchException("Checksums did not match");
+        }
+    }
+
+    private void decryptFileWithExplicitStarts(
+            RandomAccessFile input,
+            DecryptedChunkOutput decryptedChunkOutput,
+            ChunkOrdering chunkOrdering,
+            long metadataOffset)
+            throws IOException, InvalidKeyException, IllegalBlockSizeException,
+                    InvalidAlgorithmParameterException, ShortBufferException, BadPaddingException,
+                    NoSuchAlgorithmException {
+        SparseIntArray chunkLengthsByPosition =
+                getChunkLengths(chunkOrdering.starts, (int) metadataOffset);
+        int largestChunkLength = getLargestChunkLength(chunkLengthsByPosition);
+        byte[] encryptedChunkBuffer = new byte[largestChunkLength];
+        // largestChunkLength is 0 if the backup file contains zero chunks e.g. 0 kv pairs.
+        int plaintextBufferLength =
+                Math.max(0, largestChunkLength - GCM_NONCE_LENGTH_BYTES - GCM_TAG_LENGTH_BYTES);
+        byte[] plaintextChunkBuffer = new byte[plaintextBufferLength];
+
+        try (DecryptedChunkOutput output = decryptedChunkOutput.open()) {
+            for (int start : chunkOrdering.starts) {
+                int length = chunkLengthsByPosition.get(start);
+
+                input.seek(start);
+                input.readFully(encryptedChunkBuffer, 0, length);
+                int plaintextLength =
+                        decryptChunk(encryptedChunkBuffer, length, plaintextChunkBuffer);
+                outputChunk(output, plaintextChunkBuffer, plaintextLength);
+            }
+        }
+    }
+
+    private void decryptFileWithInlineLengths(
+            RandomAccessFile input, DecryptedChunkOutput decryptedChunkOutput, long metadataOffset)
+            throws MalformedEncryptedFileException, IOException, IllegalBlockSizeException,
+                    BadPaddingException, InvalidAlgorithmParameterException, ShortBufferException,
+                    InvalidKeyException, NoSuchAlgorithmException {
+        input.seek(0);
+        try (DecryptedChunkOutput output = decryptedChunkOutput.open()) {
+            while (input.getFilePointer() < metadataOffset) {
+                long start = input.getFilePointer();
+                int encryptedChunkLength = input.readInt();
+
+                if (encryptedChunkLength <= 0) {
+                    // If the length of the encrypted chunk is not positive we will not make
+                    // progress reading the file and so will loop forever.
+                    throw new MalformedEncryptedFileException(
+                            "Encrypted chunk length not positive:" + encryptedChunkLength);
+                }
+
+                if (start + encryptedChunkLength > metadataOffset) {
+                    throw new MalformedEncryptedFileException(
+                            String.format(
+                                    Locale.US,
+                                    "Encrypted chunk longer (%d) than file (%d)",
+                                    encryptedChunkLength,
+                                    metadataOffset));
+                }
+
+                byte[] plaintextChunk = new byte[encryptedChunkLength];
+                byte[] plaintext =
+                        new byte
+                                [encryptedChunkLength
+                                        - GCM_NONCE_LENGTH_BYTES
+                                        - GCM_TAG_LENGTH_BYTES];
+
+                input.readFully(plaintextChunk);
+
+                int plaintextChunkLength =
+                        decryptChunk(plaintextChunk, encryptedChunkLength, plaintext);
+                outputChunk(output, plaintext, plaintextChunkLength);
+            }
+        }
+    }
+
+    private void outputChunk(
+            DecryptedChunkOutput output, byte[] plaintextChunkBuffer, int plaintextLength)
+            throws IOException, InvalidKeyException, NoSuchAlgorithmException {
+        output.processChunk(plaintextChunkBuffer, plaintextLength);
+    }
+
+    /**
+     * Decrypts chunk and returns the length of the plaintext.
+     *
+     * @param encryptedChunkBuffer The encrypted data, prefixed by the nonce.
+     * @param encryptedChunkBufferLength The length of the encrypted chunk (including nonce).
+     * @param plaintextChunkBuffer The buffer into which to write the plaintext chunk.
+     * @return The length of the plaintext chunk.
+     */
+    private int decryptChunk(
+            byte[] encryptedChunkBuffer,
+            int encryptedChunkBufferLength,
+            byte[] plaintextChunkBuffer)
+            throws InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException,
+                    ShortBufferException, IllegalBlockSizeException {
+
+        mCipher.init(
+                Cipher.DECRYPT_MODE,
+                mSecretKey,
+                new GCMParameterSpec(
+                        GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE,
+                        encryptedChunkBuffer,
+                        0,
+                        GCM_NONCE_LENGTH_BYTES));
+
+        return mCipher.doFinal(
+                encryptedChunkBuffer,
+                GCM_NONCE_LENGTH_BYTES,
+                encryptedChunkBufferLength - GCM_NONCE_LENGTH_BYTES,
+                plaintextChunkBuffer);
+    }
+
+    /** Given all the lengths, returns the largest length. */
+    private int getLargestChunkLength(SparseIntArray lengths) {
+        int maxSeen = 0;
+        for (int i = 0; i < lengths.size(); i++) {
+            maxSeen = Math.max(maxSeen, lengths.valueAt(i));
+        }
+        return maxSeen;
+    }
+
+    /**
+     * From a list of the starting position of each chunk in the correct order of the backup data,
+     * calculates a mapping from start position to length of that chunk.
+     *
+     * @param starts The start positions of chunks, in order.
+     * @param chunkOrderingPosition Where the {@link ChunkOrdering} proto starts, used to calculate
+     *     the length of the last chunk.
+     * @return The mapping.
+     */
+    private SparseIntArray getChunkLengths(int[] starts, int chunkOrderingPosition) {
+        int[] boundaries = Arrays.copyOf(starts, starts.length + 1);
+        boundaries[boundaries.length - 1] = chunkOrderingPosition;
+        Arrays.sort(boundaries);
+
+        SparseIntArray lengths = new SparseIntArray();
+        for (int i = 0; i < boundaries.length - 1; i++) {
+            lengths.put(boundaries[i], boundaries[i + 1] - boundaries[i]);
+        }
+        return lengths;
+    }
+
+    /**
+     * Reads and decrypts the {@link ChunkOrdering} from the {@link ChunksMetadata}.
+     *
+     * @param metadata The metadata.
+     * @return The ordering.
+     * @throws InvalidProtocolBufferNanoException if there is an issue deserializing the proto.
+     */
+    private ChunkOrdering decryptChunkOrdering(ChunksMetadata metadata)
+            throws InvalidProtocolBufferNanoException, InvalidAlgorithmParameterException,
+                    InvalidKeyException, BadPaddingException, IllegalBlockSizeException,
+                    UnsupportedEncryptedFileException {
+        assertCryptoSupported(metadata);
+
+        mCipher.init(
+                Cipher.DECRYPT_MODE,
+                mSecretKey,
+                new GCMParameterSpec(
+                        GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE,
+                        metadata.chunkOrdering,
+                        0,
+                        GCM_NONCE_LENGTH_BYTES));
+
+        byte[] decrypted =
+                mCipher.doFinal(
+                        metadata.chunkOrdering,
+                        GCM_NONCE_LENGTH_BYTES,
+                        metadata.chunkOrdering.length - GCM_NONCE_LENGTH_BYTES);
+
+        return ChunkOrdering.parseFrom(decrypted);
+    }
+
+    /**
+     * Asserts that the Cipher and MessageDigest algorithms in the backup metadata are supported.
+     * For now we only support SHA-256 for checksum and 256-bit AES/GCM/NoPadding for the Cipher.
+     *
+     * @param chunksMetadata The file metadata.
+     * @throws UnsupportedEncryptedFileException if any algorithm is unsupported.
+     */
+    private void assertCryptoSupported(ChunksMetadata chunksMetadata)
+            throws UnsupportedEncryptedFileException {
+        if (chunksMetadata.checksumType != ChunksMetadataProto.SHA_256) {
+            // For now we only support SHA-256.
+            throw new UnsupportedEncryptedFileException(
+                    "Unrecognized checksum type for backup (this version of backup only supports"
+                        + " SHA-256): "
+                            + chunksMetadata.checksumType);
+        }
+
+        if (chunksMetadata.cipherType != ChunksMetadataProto.AES_256_GCM) {
+            throw new UnsupportedEncryptedFileException(
+                    "Unrecognized cipher type for backup (this version of backup only supports"
+                        + " AES-256-GCM: "
+                            + chunksMetadata.cipherType);
+        }
+    }
+
+    /**
+     * Reads the offset of the {@link ChunksMetadata} proto from the end of the file.
+     *
+     * @return The offset.
+     * @throws IOException if there is an error reading.
+     */
+    private long getChunksMetadataOffset(RandomAccessFile input) throws IOException {
+        input.seek(input.length() - BYTES_PER_LONG);
+        return input.readLong();
+    }
+
+    /**
+     * Reads the {@link ChunksMetadata} proto from the given position in the file.
+     *
+     * @param input The encrypted file.
+     * @param position The position where the proto starts.
+     * @return The proto.
+     * @throws IOException if there is an issue reading the file or deserializing the proto.
+     */
+    private ChunksMetadata getChunksMetadata(RandomAccessFile input, long position)
+            throws IOException, MalformedEncryptedFileException {
+        long length = input.length();
+        if (position >= length || position < 0) {
+            throw new MalformedEncryptedFileException(
+                    String.format(
+                            Locale.US,
+                            "%d is not valid position for chunks metadata in file of %d bytes",
+                            position,
+                            length));
+        }
+
+        // Read chunk ordering bytes
+        input.seek(position);
+        long chunksMetadataLength = input.length() - BYTES_PER_LONG - position;
+        byte[] chunksMetadataBytes = new byte[(int) chunksMetadataLength];
+        input.readFully(chunksMetadataBytes);
+
+        try {
+            return ChunksMetadata.parseFrom(chunksMetadataBytes);
+        } catch (InvalidProtocolBufferNanoException e) {
+            throw new MalformedEncryptedFileException(
+                    String.format(
+                            Locale.US,
+                            "Could not read chunks metadata at position %d of file of %d bytes",
+                            position,
+                            length));
+        }
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java
new file mode 100644
index 0000000..a938d71
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTask.java
@@ -0,0 +1,197 @@
+/*
+ * 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.encryption.tasks;
+
+import android.content.Context;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.StreamUtils;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkListing;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.concurrent.Callable;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Task which reads a stream of plaintext full backup data, chunks it, encrypts it and uploads it to
+ * the server.
+ *
+ * <p>Once the backup completes or fails, closes the input stream.
+ */
+public class EncryptedFullBackupTask implements Callable<Void> {
+    private static final String TAG = "EncryptedFullBackupTask";
+
+    private static final int MIN_CHUNK_SIZE_BYTES = 2 * 1024;
+    private static final int MAX_CHUNK_SIZE_BYTES = 64 * 1024;
+    private static final int AVERAGE_CHUNK_SIZE_BYTES = 4 * 1024;
+
+    // TODO(b/69350270): Remove this hard-coded salt and related logic once we feel confident that
+    // incremental backup has happened at least once for all existing packages/users since we moved
+    // to
+    // using a randomly generated salt.
+    //
+    // The hard-coded fingerprint mixer salt was used for a short time period before replaced by one
+    // that is randomly generated on initial non-incremental backup and stored in ChunkListing to be
+    // reused for succeeding incremental backups. If an old ChunkListing does not have a
+    // fingerprint_mixer_salt, we assume that it was last backed up before a randomly generated salt
+    // is used so we use the hardcoded salt and set ChunkListing#fingerprint_mixer_salt to this
+    // value.
+    // Eventually all backup ChunkListings will have this field set and then we can remove the
+    // default
+    // value in the code.
+    static final byte[] DEFAULT_FINGERPRINT_MIXER_SALT =
+            Arrays.copyOf(new byte[] {20, 23}, FingerprintMixer.SALT_LENGTH_BYTES);
+
+    private final ProtoStore<ChunkListing> mChunkListingStore;
+    private final TertiaryKeyManager mTertiaryKeyManager;
+    private final InputStream mInputStream;
+    private final EncryptedBackupTask mTask;
+    private final String mPackageName;
+    private final SecureRandom mSecureRandom;
+
+    /** Creates a new instance with the default min, max and average chunk sizes. */
+    public static EncryptedFullBackupTask newInstance(
+            Context context,
+            CryptoBackupServer cryptoBackupServer,
+            SecureRandom secureRandom,
+            RecoverableKeyStoreSecondaryKey secondaryKey,
+            String packageName,
+            InputStream inputStream)
+            throws IOException {
+        EncryptedBackupTask encryptedBackupTask =
+                new EncryptedBackupTask(
+                        cryptoBackupServer,
+                        secureRandom,
+                        packageName,
+                        new BackupStreamEncrypter(
+                                inputStream,
+                                MIN_CHUNK_SIZE_BYTES,
+                                MAX_CHUNK_SIZE_BYTES,
+                                AVERAGE_CHUNK_SIZE_BYTES));
+        TertiaryKeyManager tertiaryKeyManager =
+                new TertiaryKeyManager(
+                        context,
+                        secureRandom,
+                        TertiaryKeyRotationScheduler.getInstance(context),
+                        secondaryKey,
+                        packageName);
+
+        return new EncryptedFullBackupTask(
+                ProtoStore.createChunkListingStore(context),
+                tertiaryKeyManager,
+                encryptedBackupTask,
+                inputStream,
+                packageName,
+                new SecureRandom());
+    }
+
+    @VisibleForTesting
+    EncryptedFullBackupTask(
+            ProtoStore<ChunkListing> chunkListingStore,
+            TertiaryKeyManager tertiaryKeyManager,
+            EncryptedBackupTask task,
+            InputStream inputStream,
+            String packageName,
+            SecureRandom secureRandom) {
+        mChunkListingStore = chunkListingStore;
+        mTertiaryKeyManager = tertiaryKeyManager;
+        mInputStream = inputStream;
+        mTask = task;
+        mPackageName = packageName;
+        mSecureRandom = secureRandom;
+    }
+
+    @Override
+    public Void call() throws Exception {
+        try {
+            Optional<ChunkListing> maybeOldChunkListing =
+                    mChunkListingStore.loadProto(mPackageName);
+
+            if (maybeOldChunkListing.isPresent()) {
+                Slog.i(TAG, "Found previous chunk listing for " + mPackageName);
+            }
+
+            // If the key has been rotated then we must re-encrypt all of the backup data.
+            if (mTertiaryKeyManager.wasKeyRotated()) {
+                Slog.i(
+                        TAG,
+                        "Key was rotated or newly generated for "
+                                + mPackageName
+                                + ", so performing a full backup.");
+                maybeOldChunkListing = Optional.empty();
+                mChunkListingStore.deleteProto(mPackageName);
+            }
+
+            SecretKey tertiaryKey = mTertiaryKeyManager.getKey();
+            WrappedKeyProto.WrappedKey wrappedTertiaryKey = mTertiaryKeyManager.getWrappedKey();
+
+            ChunkListing newChunkListing;
+            if (!maybeOldChunkListing.isPresent()) {
+                byte[] fingerprintMixerSalt = new byte[FingerprintMixer.SALT_LENGTH_BYTES];
+                mSecureRandom.nextBytes(fingerprintMixerSalt);
+                newChunkListing =
+                        mTask.performNonIncrementalBackup(
+                                tertiaryKey, wrappedTertiaryKey, fingerprintMixerSalt);
+            } else {
+                ChunkListing oldChunkListing = maybeOldChunkListing.get();
+
+                if (oldChunkListing.fingerprintMixerSalt == null
+                        || oldChunkListing.fingerprintMixerSalt.length == 0) {
+                    oldChunkListing.fingerprintMixerSalt = DEFAULT_FINGERPRINT_MIXER_SALT;
+                }
+
+                newChunkListing =
+                        mTask.performIncrementalBackup(
+                                tertiaryKey, wrappedTertiaryKey, oldChunkListing);
+            }
+
+            mChunkListingStore.saveProto(mPackageName, newChunkListing);
+            Slog.v(TAG, "Saved chunk listing for " + mPackageName);
+        } catch (IOException e) {
+            Slog.e(TAG, "Storage exception, wiping state");
+            mChunkListingStore.deleteProto(mPackageName);
+            throw e;
+        } finally {
+            StreamUtils.closeQuietly(mInputStream);
+        }
+
+        return null;
+    }
+
+    /**
+     * Signals to the task that the backup has been cancelled. If the upload has not yet started
+     * then the task will not upload any data to the server or save the new chunk listing.
+     *
+     * <p>You must then terminate the input stream.
+     */
+    public void cancel() {
+        mTask.cancel();
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java
new file mode 100644
index 0000000..04381af
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTask.java
@@ -0,0 +1,137 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.annotation.Nullable;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.FullRestoreDataProcessor;
+import com.android.server.backup.encryption.FullRestoreDownloader;
+import com.android.server.backup.encryption.StreamUtils;
+import com.android.server.backup.encryption.chunking.DecryptedChunkFileOutput;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+
+/** Downloads the encrypted backup file, decrypts it and passes the data to backup manager. */
+public class EncryptedFullRestoreTask implements FullRestoreDataProcessor {
+    private static final String DEFAULT_TEMPORARY_FOLDER = "encrypted_restore_temp";
+    private static final String ENCRYPTED_FILE_NAME = "encrypted_restore";
+    private static final String DECRYPTED_FILE_NAME = "decrypted_restore";
+
+    private final FullRestoreToFileTask mFullRestoreToFileTask;
+    private final BackupFileDecryptorTask mBackupFileDecryptorTask;
+    private final File mEncryptedFile;
+    private final File mDecryptedFile;
+    @Nullable private InputStream mDecryptedFileInputStream;
+
+    /**
+     * Creates a new task which stores temporary files in the files directory.
+     *
+     * @param fullRestoreDownloader which will download the backup file
+     * @param tertiaryKey which the backup file is encrypted with
+     */
+    public static EncryptedFullRestoreTask newInstance(
+            Context context, FullRestoreDownloader fullRestoreDownloader, SecretKey tertiaryKey)
+            throws NoSuchAlgorithmException, NoSuchPaddingException {
+        File temporaryFolder = new File(context.getFilesDir(), DEFAULT_TEMPORARY_FOLDER);
+        temporaryFolder.mkdirs();
+        return new EncryptedFullRestoreTask(
+                temporaryFolder, fullRestoreDownloader, new BackupFileDecryptorTask(tertiaryKey));
+    }
+
+    @VisibleForTesting
+    EncryptedFullRestoreTask(
+            File temporaryFolder,
+            FullRestoreDownloader fullRestoreDownloader,
+            BackupFileDecryptorTask backupFileDecryptorTask) {
+        checkArgument(temporaryFolder.isDirectory(), "Temporary folder must be existing directory");
+
+        mEncryptedFile = new File(temporaryFolder, ENCRYPTED_FILE_NAME);
+        mDecryptedFile = new File(temporaryFolder, DECRYPTED_FILE_NAME);
+
+        mFullRestoreToFileTask = new FullRestoreToFileTask(fullRestoreDownloader);
+        mBackupFileDecryptorTask = backupFileDecryptorTask;
+    }
+
+    /**
+     * Reads the next decrypted bytes into the given buffer.
+     *
+     * <p>During the first call this method will download the backup file from the server, decrypt
+     * it and save it to disk. It will then read the bytes from the file on disk.
+     *
+     * <p>Once this method has read all the bytes of the file, the caller must call {@link #finish}
+     * to clean up.
+     *
+     * @return the number of bytes read, or {@code -1} on reaching the end of the file
+     */
+    @Override
+    public int readNextChunk(byte[] buffer) throws IOException {
+        if (mDecryptedFileInputStream == null) {
+            try {
+                mDecryptedFileInputStream = downloadAndDecryptBackup();
+            } catch (BadPaddingException
+                    | InvalidKeyException
+                    | NoSuchAlgorithmException
+                    | IllegalBlockSizeException
+                    | ShortBufferException
+                    | EncryptedRestoreException
+                    | InvalidAlgorithmParameterException e) {
+                throw new IOException("Encryption issue", e);
+            }
+        }
+
+        return mDecryptedFileInputStream.read(buffer);
+    }
+
+    private InputStream downloadAndDecryptBackup()
+            throws IOException, BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
+                    IllegalBlockSizeException, ShortBufferException, EncryptedRestoreException,
+                    InvalidAlgorithmParameterException {
+        mFullRestoreToFileTask.restoreToFile(mEncryptedFile);
+        mBackupFileDecryptorTask.decryptFile(
+                mEncryptedFile, new DecryptedChunkFileOutput(mDecryptedFile));
+        mEncryptedFile.delete();
+        return new BufferedInputStream(new FileInputStream(mDecryptedFile));
+    }
+
+    /** Cleans up temporary files. */
+    @Override
+    public void finish(FullRestoreDownloader.FinishType unusedFinishType) {
+        // The download is finished and log sent during RestoreToFileTask#restoreToFile(), so we
+        // don't need to do either of those things here.
+
+        StreamUtils.closeQuietly(mDecryptedFileInputStream);
+        mEncryptedFile.delete();
+        mDecryptedFile.delete();
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java
new file mode 100644
index 0000000..619438c
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTask.java
@@ -0,0 +1,244 @@
+/*
+ * 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.encryption.tasks;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupDataInput;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.LockScreenRequiredException;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.KeyValueListingProto;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.util.Optional;
+
+// TODO(b/141975695): Create a base class for EncryptedKvBackupTask and EncryptedFullBackupTask.
+/** Performs encrypted key value backup, handling rotating the tertiary key as necessary. */
+public class EncryptedKvBackupTask {
+    private static final String TAG = "EncryptedKvBackupTask";
+
+    private final TertiaryKeyManager mTertiaryKeyManager;
+    private final RecoverableKeyStoreSecondaryKey mSecondaryKey;
+    private final ProtoStore<KeyValueListingProto.KeyValueListing> mKeyValueListingStore;
+    private final ProtoStore<ChunksMetadataProto.ChunkListing> mChunkListingStore;
+    private final KvBackupEncrypter mKvBackupEncrypter;
+    private final EncryptedBackupTask mEncryptedBackupTask;
+    private final String mPackageName;
+
+    /** Constructs new instances of {@link EncryptedKvBackupTask}. */
+    public static class EncryptedKvBackupTaskFactory {
+        /**
+         * Creates a new instance.
+         *
+         * <p>Either initializes encrypted backup or loads an existing secondary key as necessary.
+         *
+         * @param cryptoSettings to load secondary key state from
+         * @param fileDescriptor to read the backup data from
+         */
+        public EncryptedKvBackupTask newInstance(
+                Context context,
+                SecureRandom secureRandom,
+                CryptoBackupServer cryptoBackupServer,
+                CryptoSettings cryptoSettings,
+                RecoverableKeyStoreSecondaryKeyManager
+                                .RecoverableKeyStoreSecondaryKeyManagerProvider
+                        recoverableSecondaryKeyManagerProvider,
+                ParcelFileDescriptor fileDescriptor,
+                String packageName)
+                throws IOException, UnrecoverableKeyException, LockScreenRequiredException,
+                        InternalRecoveryServiceException, InvalidKeyException {
+            RecoverableKeyStoreSecondaryKey secondaryKey =
+                    new InitializeRecoverableSecondaryKeyTask(
+                                    context,
+                                    cryptoSettings,
+                                    recoverableSecondaryKeyManagerProvider.get(),
+                                    cryptoBackupServer)
+                            .run();
+            KvBackupEncrypter backupEncrypter =
+                    new KvBackupEncrypter(new BackupDataInput(fileDescriptor.getFileDescriptor()));
+            TertiaryKeyManager tertiaryKeyManager =
+                    new TertiaryKeyManager(
+                            context,
+                            secureRandom,
+                            TertiaryKeyRotationScheduler.getInstance(context),
+                            secondaryKey,
+                            packageName);
+
+            return new EncryptedKvBackupTask(
+                    tertiaryKeyManager,
+                    ProtoStore.createKeyValueListingStore(context),
+                    secondaryKey,
+                    ProtoStore.createChunkListingStore(context),
+                    backupEncrypter,
+                    new EncryptedBackupTask(
+                            cryptoBackupServer, secureRandom, packageName, backupEncrypter),
+                    packageName);
+        }
+    }
+
+    @VisibleForTesting
+    EncryptedKvBackupTask(
+            TertiaryKeyManager tertiaryKeyManager,
+            ProtoStore<KeyValueListingProto.KeyValueListing> keyValueListingStore,
+            RecoverableKeyStoreSecondaryKey secondaryKey,
+            ProtoStore<ChunksMetadataProto.ChunkListing> chunkListingStore,
+            KvBackupEncrypter kvBackupEncrypter,
+            EncryptedBackupTask encryptedBackupTask,
+            String packageName) {
+        mTertiaryKeyManager = tertiaryKeyManager;
+        mSecondaryKey = secondaryKey;
+        mKeyValueListingStore = keyValueListingStore;
+        mChunkListingStore = chunkListingStore;
+        mKvBackupEncrypter = kvBackupEncrypter;
+        mEncryptedBackupTask = encryptedBackupTask;
+        mPackageName = packageName;
+    }
+
+    /**
+     * Reads backup data from the file descriptor provided in the construtor, encrypts it and
+     * uploads it to the server.
+     *
+     * <p>The {@code incremental} flag indicates if the backup data provided is incremental or a
+     * complete set. Incremental backup is not possible if no previous crypto state exists, or the
+     * tertiary key must be rotated in the next backup. If the caller requests incremental backup
+     * but it is not possible, then the backup will not start and this method will throw {@link
+     * NonIncrementalBackupRequiredException}.
+     *
+     * <p>TODO(b/70704456): Update return code to indicate that we require non-incremental backup.
+     *
+     * @param incremental {@code true} if the data provided is a diff from the previous backup,
+     *     {@code false} if it is a complete set
+     * @throws NonIncrementalBackupRequiredException if the caller provides an incremental backup but the task
+     *     requires non-incremental backup
+     */
+    public void performBackup(boolean incremental)
+            throws GeneralSecurityException, IOException, NoSuchMethodException,
+            InstantiationException, IllegalAccessException, InvocationTargetException,
+            NonIncrementalBackupRequiredException {
+        if (mTertiaryKeyManager.wasKeyRotated()) {
+            Slog.d(TAG, "Tertiary key is new so clearing package state.");
+            deleteListings(mPackageName);
+        }
+
+        Optional<Pair<KeyValueListingProto.KeyValueListing, ChunksMetadataProto.ChunkListing>>
+                oldListings = getListingsAndEnsureConsistency(mPackageName);
+
+        if (oldListings.isPresent() && !incremental) {
+            Slog.d(
+                    TAG,
+                    "Non-incremental backup requested but incremental state existed, clearing it");
+            deleteListings(mPackageName);
+            oldListings = Optional.empty();
+        }
+
+        if (!oldListings.isPresent() && incremental) {
+            // If we don't have any state then we require a non-incremental backup, but this backup
+            // is incremental.
+            throw new NonIncrementalBackupRequiredException();
+        }
+
+        if (oldListings.isPresent()) {
+            mKvBackupEncrypter.setOldKeyValueListing(oldListings.get().first);
+        }
+
+        ChunksMetadataProto.ChunkListing newChunkListing;
+        if (oldListings.isPresent()) {
+            Slog.v(TAG, "Old listings existed, performing incremental backup");
+            newChunkListing =
+                    mEncryptedBackupTask.performIncrementalBackup(
+                            mTertiaryKeyManager.getKey(),
+                            mTertiaryKeyManager.getWrappedKey(),
+                            oldListings.get().second);
+        } else {
+            Slog.v(TAG, "Old listings did not exist, performing non-incremental backup");
+            // kv backups don't use this salt because they don't involve content-defined chunking.
+            byte[] fingerprintMixerSalt = null;
+            newChunkListing =
+                    mEncryptedBackupTask.performNonIncrementalBackup(
+                            mTertiaryKeyManager.getKey(),
+                            mTertiaryKeyManager.getWrappedKey(),
+                            fingerprintMixerSalt);
+        }
+
+        Slog.v(TAG, "Backup and upload succeeded, saving new listings");
+        saveListings(mPackageName, mKvBackupEncrypter.getNewKeyValueListing(), newChunkListing);
+    }
+
+    private Optional<Pair<KeyValueListingProto.KeyValueListing, ChunksMetadataProto.ChunkListing>>
+            getListingsAndEnsureConsistency(String packageName)
+                    throws IOException, InvocationTargetException, NoSuchMethodException,
+                            InstantiationException, IllegalAccessException {
+        Optional<KeyValueListingProto.KeyValueListing> keyValueListing =
+                mKeyValueListingStore.loadProto(packageName);
+        Optional<ChunksMetadataProto.ChunkListing> chunkListing =
+                mChunkListingStore.loadProto(packageName);
+
+        // Normally either both protos exist or neither exist, but we correct this just in case.
+        boolean bothPresent = keyValueListing.isPresent() && chunkListing.isPresent();
+        if (!bothPresent) {
+            Slog.d(
+                    TAG,
+                    "Both listing were not present, clearing state, key value="
+                            + keyValueListing.isPresent()
+                            + ", chunk="
+                            + chunkListing.isPresent());
+            deleteListings(packageName);
+            return Optional.empty();
+        }
+
+        return Optional.of(Pair.create(keyValueListing.get(), chunkListing.get()));
+    }
+
+    private void saveListings(
+            String packageName,
+            KeyValueListingProto.KeyValueListing keyValueListing,
+            ChunksMetadataProto.ChunkListing chunkListing) {
+        try {
+            mKeyValueListingStore.saveProto(packageName, keyValueListing);
+            mChunkListingStore.saveProto(packageName, chunkListing);
+        } catch (IOException e) {
+            // If a problem occurred while saving either listing then they may be inconsistent, so
+            // delete
+            // both.
+            Slog.w(TAG, "Unable to save listings, deleting both for consistency", e);
+            deleteListings(packageName);
+        }
+    }
+
+    private void deleteListings(String packageName) {
+        mKeyValueListingStore.deleteProto(packageName);
+        mChunkListingStore.deleteProto(packageName);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.java
new file mode 100644
index 0000000..12b4459
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTask.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.encryption.tasks;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.backup.BackupDataOutput;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.FullRestoreDownloader;
+import com.android.server.backup.encryption.chunking.ChunkHasher;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.RestoreKeyFetcher;
+import com.android.server.backup.encryption.kv.DecryptedChunkKvOutput;
+import com.android.server.backup.encryption.protos.nano.KeyValuePairProto;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+
+/**
+ * Performs a key value restore by downloading the backup set, decrypting it and writing it to the
+ * file provided by backup manager.
+ */
+public class EncryptedKvRestoreTask {
+    private static final String ENCRYPTED_FILE_NAME = "encrypted_kv";
+
+    private final File mTemporaryFolder;
+    private final ChunkHasher mChunkHasher;
+    private final FullRestoreToFileTask mFullRestoreToFileTask;
+    private final BackupFileDecryptorTask mBackupFileDecryptorTask;
+
+    /** Constructs new instances of the task. */
+    public static class EncryptedKvRestoreTaskFactory {
+        /**
+         * Constructs a new instance.
+         *
+         * <p>Fetches the appropriate secondary key and uses this to unwrap the tertiary key. Stores
+         * temporary files in {@link Context#getFilesDir()}.
+         */
+        public EncryptedKvRestoreTask newInstance(
+                Context context,
+                RecoverableKeyStoreSecondaryKeyManager
+                                .RecoverableKeyStoreSecondaryKeyManagerProvider
+                        recoverableSecondaryKeyManagerProvider,
+                FullRestoreDownloader fullRestoreDownloader,
+                String secondaryKeyAlias,
+                WrappedKeyProto.WrappedKey wrappedTertiaryKey)
+                throws EncryptedRestoreException, NoSuchAlgorithmException, NoSuchPaddingException,
+                        KeyException, InvalidAlgorithmParameterException {
+            SecretKey tertiaryKey =
+                    RestoreKeyFetcher.unwrapTertiaryKey(
+                            recoverableSecondaryKeyManagerProvider,
+                            secondaryKeyAlias,
+                            wrappedTertiaryKey);
+
+            return new EncryptedKvRestoreTask(
+                    context.getFilesDir(),
+                    new ChunkHasher(tertiaryKey),
+                    new FullRestoreToFileTask(fullRestoreDownloader),
+                    new BackupFileDecryptorTask(tertiaryKey));
+        }
+    }
+
+    @VisibleForTesting
+    EncryptedKvRestoreTask(
+            File temporaryFolder,
+            ChunkHasher chunkHasher,
+            FullRestoreToFileTask fullRestoreToFileTask,
+            BackupFileDecryptorTask backupFileDecryptorTask) {
+        checkArgument(
+                temporaryFolder.isDirectory(), "Temporary folder must be an existing directory");
+
+        mTemporaryFolder = temporaryFolder;
+        mChunkHasher = chunkHasher;
+        mFullRestoreToFileTask = fullRestoreToFileTask;
+        mBackupFileDecryptorTask = backupFileDecryptorTask;
+    }
+
+    /**
+     * Runs the restore, writing the pairs in lexicographical order to the given file descriptor.
+     *
+     * <p>This will block for the duration of the restore.
+     *
+     * @throws EncryptedRestoreException if there is a problem decrypting or verifying the backup
+     */
+    public void getRestoreData(ParcelFileDescriptor output)
+            throws IOException, EncryptedRestoreException, BadPaddingException,
+                    InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+                    IllegalBlockSizeException, ShortBufferException, InvalidKeyException {
+        File encryptedFile = new File(mTemporaryFolder, ENCRYPTED_FILE_NAME);
+        try {
+            downloadDecryptAndWriteBackup(encryptedFile, output);
+        } finally {
+            encryptedFile.delete();
+        }
+    }
+
+    private void downloadDecryptAndWriteBackup(File encryptedFile, ParcelFileDescriptor output)
+            throws EncryptedRestoreException, IOException, BadPaddingException, InvalidKeyException,
+                    NoSuchAlgorithmException, IllegalBlockSizeException, ShortBufferException,
+                    InvalidAlgorithmParameterException {
+        mFullRestoreToFileTask.restoreToFile(encryptedFile);
+        DecryptedChunkKvOutput decryptedChunkKvOutput = new DecryptedChunkKvOutput(mChunkHasher);
+        mBackupFileDecryptorTask.decryptFile(encryptedFile, decryptedChunkKvOutput);
+
+        BackupDataOutput backupDataOutput = new BackupDataOutput(output.getFileDescriptor());
+        for (KeyValuePairProto.KeyValuePair pair : decryptedChunkKvOutput.getPairs()) {
+            backupDataOutput.writeEntityHeader(pair.key, pair.value.length);
+            backupDataOutput.writeEntityData(pair.value, pair.value.length);
+        }
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java
new file mode 100644
index 0000000..82f83f9
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTask.java
@@ -0,0 +1,87 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.FullRestoreDownloader;
+import com.android.server.backup.encryption.FullRestoreDownloader.FinishType;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Reads a stream from a {@link FullRestoreDownloader} and writes it to a file for consumption by
+ * {@link BackupFileDecryptorTask}.
+ */
+public class FullRestoreToFileTask {
+    /**
+     * Maximum number of bytes which the framework can request from the full restore data stream in
+     * one call to {@link BackupTransport#getNextFullRestoreDataChunk}.
+     */
+    public static final int MAX_BYTES_FULL_RESTORE_CHUNK = 1024 * 32;
+
+    /** Returned when the end of a backup stream has been reached. */
+    private static final int END_OF_STREAM = -1;
+
+    private final FullRestoreDownloader mFullRestoreDownloader;
+    private final int mBufferSize;
+
+    /**
+     * Constructs a new instance which reads from the given package wrapper, using a buffer of size
+     * {@link #MAX_BYTES_FULL_RESTORE_CHUNK}.
+     */
+    public FullRestoreToFileTask(FullRestoreDownloader fullRestoreDownloader) {
+        this(fullRestoreDownloader, MAX_BYTES_FULL_RESTORE_CHUNK);
+    }
+
+    @VisibleForTesting
+    FullRestoreToFileTask(FullRestoreDownloader fullRestoreDownloader, int bufferSize) {
+        checkArgument(bufferSize > 0, "Buffer must have positive size");
+
+        this.mFullRestoreDownloader = fullRestoreDownloader;
+        this.mBufferSize = bufferSize;
+    }
+
+    /**
+     * Downloads the backup file from the server and writes it to the given file.
+     *
+     * <p>At the end of the download (success or failure), closes the connection and sends a
+     * Clearcut log.
+     */
+    public void restoreToFile(File targetFile) throws IOException {
+        try (BufferedOutputStream outputStream =
+                new BufferedOutputStream(new FileOutputStream(targetFile))) {
+            byte[] buffer = new byte[mBufferSize];
+            int bytesRead = mFullRestoreDownloader.readNextChunk(buffer);
+            while (bytesRead != END_OF_STREAM) {
+                outputStream.write(buffer, /* off=*/ 0, bytesRead);
+                bytesRead = mFullRestoreDownloader.readNextChunk(buffer);
+            }
+
+            outputStream.flush();
+
+            mFullRestoreDownloader.finish(FinishType.FINISHED);
+        } catch (IOException e) {
+            mFullRestoreDownloader.finish(FinishType.TRANSFER_FAILURE);
+            throw e;
+        }
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTask.java
new file mode 100644
index 0000000..d436554
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTask.java
@@ -0,0 +1,157 @@
+/*
+ * 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.encryption.tasks;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.LockScreenRequiredException;
+import android.security.keystore.recovery.RecoveryController;
+import android.util.Slog;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+
+import java.security.InvalidKeyException;
+import java.security.UnrecoverableKeyException;
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * Initializes the device for encrypted backup, through generating a secondary key, and setting its
+ * alias in the settings.
+ *
+ * <p>If the device is already initialized, this is a no-op.
+ */
+public class InitializeRecoverableSecondaryKeyTask {
+    private static final String TAG = "InitializeRecoverableSecondaryKeyTask";
+
+    private final Context mContext;
+    private final CryptoSettings mCryptoSettings;
+    private final RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+    private final CryptoBackupServer mBackupServer;
+
+    /**
+     * A new instance.
+     *
+     * @param cryptoSettings Settings to store the active key alias.
+     * @param secondaryKeyManager Key manager to generate the new active secondary key.
+     * @param backupServer Server with which to sync the active key alias.
+     */
+    public InitializeRecoverableSecondaryKeyTask(
+            Context context,
+            CryptoSettings cryptoSettings,
+            RecoverableKeyStoreSecondaryKeyManager secondaryKeyManager,
+            CryptoBackupServer backupServer) {
+        mContext = context;
+        mCryptoSettings = cryptoSettings;
+        mSecondaryKeyManager = secondaryKeyManager;
+        mBackupServer = backupServer;
+    }
+
+    /**
+     * Initializes the device for encrypted backup, by generating a recoverable secondary key, then
+     * sending that alias to the backup server and saving it in local settings.
+     *
+     * <p>If there is already an active secondary key then does nothing. If the active secondary key
+     * is destroyed then throws {@link InvalidKeyException}.
+     *
+     * <p>If a key rotation is pending and able to finish (i.e., the new key has synced with the
+     * remote trusted hardware module), then it completes the rotation before returning the key.
+     *
+     * @return The active secondary key.
+     * @throws InvalidKeyException if the secondary key is in a bad state.
+     */
+    public RecoverableKeyStoreSecondaryKey run()
+            throws InvalidKeyException, LockScreenRequiredException, UnrecoverableKeyException,
+                    InternalRecoveryServiceException {
+        // Complete any pending key rotations
+        new RotateSecondaryKeyTask(
+                        mContext,
+                        mSecondaryKeyManager,
+                        mBackupServer,
+                        mCryptoSettings,
+                        RecoveryController.getInstance(mContext))
+                .run();
+
+        return runInternal();
+    }
+
+    private RecoverableKeyStoreSecondaryKey runInternal()
+            throws InvalidKeyException, LockScreenRequiredException, UnrecoverableKeyException,
+                    InternalRecoveryServiceException {
+        Optional<RecoverableKeyStoreSecondaryKey> maybeActiveKey = loadFromSetting();
+
+        if (maybeActiveKey.isPresent()) {
+            assertKeyNotDestroyed(maybeActiveKey.get());
+            Slog.d(TAG, "Secondary key already initialized: " + maybeActiveKey.get().getAlias());
+            return maybeActiveKey.get();
+        }
+
+        Slog.v(TAG, "Initializing for crypto: generating a secondary key.");
+        RecoverableKeyStoreSecondaryKey key = mSecondaryKeyManager.generate();
+
+        String alias = key.getAlias();
+        Slog.i(TAG, "Generated new secondary key " + alias);
+
+        // No tertiary keys yet as we are creating a brand new secondary (without rotation).
+        mBackupServer.setActiveSecondaryKeyAlias(alias, /*tertiaryKeys=*/ Collections.emptyMap());
+        Slog.v(TAG, "Successfully synced %s " + alias + " with server.");
+
+        mCryptoSettings.initializeWithKeyAlias(alias);
+        Slog.v(TAG, "Successfully saved " + alias + " as active secondary to disk.");
+
+        return key;
+    }
+
+    private void assertKeyNotDestroyed(RecoverableKeyStoreSecondaryKey key)
+            throws InvalidKeyException {
+        if (key.getStatus(mContext) == RecoverableKeyStoreSecondaryKey.Status.DESTROYED) {
+            throw new InvalidKeyException("Key destroyed: " + key.getAlias());
+        }
+    }
+
+    private Optional<RecoverableKeyStoreSecondaryKey> loadFromSetting()
+            throws InvalidKeyException, UnrecoverableKeyException,
+                    InternalRecoveryServiceException {
+
+        // TODO: b/141856950.
+        if (!mCryptoSettings.getIsInitialized()) {
+            return Optional.empty();
+        }
+
+        Optional<String> maybeAlias = mCryptoSettings.getActiveSecondaryKeyAlias();
+        if (!maybeAlias.isPresent()) {
+            throw new InvalidKeyException(
+                    "Settings said crypto was initialized, but there was no active secondary"
+                            + " alias");
+        }
+
+        String alias = maybeAlias.get();
+
+        Optional<RecoverableKeyStoreSecondaryKey> key;
+        key = mSecondaryKeyManager.get(alias);
+
+        if (!key.isPresent()) {
+            throw new InvalidKeyException(
+                    "Initialized with key but it was not in key store: " + alias);
+        }
+
+        return key;
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MalformedEncryptedFileException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MalformedEncryptedFileException.java
new file mode 100644
index 0000000..78c370b
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MalformedEncryptedFileException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.encryption.tasks;
+
+/** Exception thrown when we cannot parse the encrypted backup file. */
+public class MalformedEncryptedFileException extends EncryptedRestoreException {
+    public MalformedEncryptedFileException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java
new file mode 100644
index 0000000..1e4f43b
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/MessageDigestMismatchException.java
@@ -0,0 +1,27 @@
+/*
+ * 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.encryption.tasks;
+
+/**
+ * Error thrown if the message digest of the plaintext backup does not match that in the {@link
+ * com.android.server.backup.encryption.protos.ChunksMetadataProto.ChunkOrdering}.
+ */
+public class MessageDigestMismatchException extends EncryptedRestoreException {
+    public MessageDigestMismatchException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NoActiveSecondaryKeyException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NoActiveSecondaryKeyException.java
new file mode 100644
index 0000000..72e8a89
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NoActiveSecondaryKeyException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.encryption.tasks;
+
+/**
+ * Error thrown if attempting to rotate key when there is no current active secondary key set
+ * locally. This means the device needs to re-initialize, asking the backup server what the active
+ * secondary key is.
+ */
+public class NoActiveSecondaryKeyException extends Exception {
+    public NoActiveSecondaryKeyException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java
new file mode 100644
index 0000000..a3eda7d
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/NonIncrementalBackupRequiredException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.encryption.tasks;
+
+// TODO(141840878): Update documentation.
+/**
+ * Exception thrown when the framework provides an incremental backup but the transport requires a
+ * non-incremental backup.
+ */
+public class NonIncrementalBackupRequiredException extends Exception {}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTask.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTask.java
new file mode 100644
index 0000000..d58cb66
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTask.java
@@ -0,0 +1,270 @@
+/*
+ * 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.encryption.tasks;
+
+import static android.os.Build.VERSION_CODES.P;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+import android.util.Slog;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.KeyWrapUtils;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyStore;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+/**
+ * Finishes a rotation for a {@link
+ * com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey}.
+ */
+public class RotateSecondaryKeyTask {
+    private static final String TAG = "RotateSecondaryKeyTask";
+
+    private final Context mContext;
+    private final RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+    private final CryptoBackupServer mBackupServer;
+    private final CryptoSettings mCryptoSettings;
+    private final RecoveryController mRecoveryController;
+
+    /**
+     * A new instance.
+     *
+     * @param secondaryKeyManager For loading the currently active and next secondary key.
+     * @param backupServer For loading and storing tertiary keys and for setting active secondary
+     *     key.
+     * @param cryptoSettings For checking the stored aliases for the next and active key.
+     * @param recoveryController For communicating with the Framework apis.
+     */
+    public RotateSecondaryKeyTask(
+            Context context,
+            RecoverableKeyStoreSecondaryKeyManager secondaryKeyManager,
+            CryptoBackupServer backupServer,
+            CryptoSettings cryptoSettings,
+            RecoveryController recoveryController) {
+        mContext = context;
+        mSecondaryKeyManager = checkNotNull(secondaryKeyManager);
+        mCryptoSettings = checkNotNull(cryptoSettings);
+        mBackupServer = checkNotNull(backupServer);
+        mRecoveryController = checkNotNull(recoveryController);
+    }
+
+    /** Runs the task. */
+    public void run() {
+        // Never run more than one of these at the same time.
+        synchronized (RotateSecondaryKeyTask.class) {
+            runInternal();
+        }
+    }
+
+    private void runInternal() {
+        Optional<RecoverableKeyStoreSecondaryKey> maybeNextKey;
+        try {
+            maybeNextKey = getNextKey();
+        } catch (Exception e) {
+            Slog.e(TAG, "Error checking for next key", e);
+            return;
+        }
+
+        if (!maybeNextKey.isPresent()) {
+            Slog.d(TAG, "No secondary key rotation task pending. Exiting.");
+            return;
+        }
+
+        RecoverableKeyStoreSecondaryKey nextKey = maybeNextKey.get();
+        boolean isReady;
+        try {
+            isReady = isSecondaryKeyRotationReady(nextKey);
+        } catch (InternalRecoveryServiceException e) {
+            Slog.e(TAG, "Error encountered checking whether next secondary key is synced", e);
+            return;
+        }
+
+        if (!isReady) {
+            return;
+        }
+
+        try {
+            rotateToKey(nextKey);
+        } catch (Exception e) {
+            Slog.e(TAG, "Error trying to rotate to new secondary key", e);
+        }
+    }
+
+    private Optional<RecoverableKeyStoreSecondaryKey> getNextKey()
+            throws InternalRecoveryServiceException, UnrecoverableKeyException {
+        Optional<String> maybeNextAlias = mCryptoSettings.getNextSecondaryKeyAlias();
+        if (!maybeNextAlias.isPresent()) {
+            return Optional.empty();
+        }
+        return mSecondaryKeyManager.get(maybeNextAlias.get());
+    }
+
+    private boolean isSecondaryKeyRotationReady(RecoverableKeyStoreSecondaryKey nextKey)
+            throws InternalRecoveryServiceException {
+        String nextAlias = nextKey.getAlias();
+        Slog.i(TAG, "Key rotation to " + nextAlias + " is pending. Checking key sync status.");
+        int status = mRecoveryController.getRecoveryStatus(nextAlias);
+
+        if (status == RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE) {
+            Slog.e(
+                    TAG,
+                    "Permanent failure to sync " + nextAlias + ". Cannot possibly rotate to it.");
+            mCryptoSettings.removeNextSecondaryKeyAlias();
+            return false;
+        }
+
+        if (status == RecoveryController.RECOVERY_STATUS_SYNCED) {
+            Slog.i(TAG, "Secondary key " + nextAlias + " has now synced! Commencing rotation.");
+        } else {
+            Slog.i(TAG, "Sync still pending for " + nextAlias);
+        }
+        return status == RecoveryController.RECOVERY_STATUS_SYNCED;
+    }
+
+    /**
+     * @throws ActiveSecondaryNotInKeychainException if the currently active secondary key is not in
+     *     the keychain.
+     * @throws IOException if there is an IO issue communicating with the server or loading from
+     *     disk.
+     * @throws NoActiveSecondaryKeyException if there is no active key set.
+     * @throws IllegalBlockSizeException if there is an issue decrypting a tertiary key.
+     * @throws InvalidKeyException if any of the secondary keys cannot be used for wrapping or
+     *     unwrapping tertiary keys.
+     */
+    private void rotateToKey(RecoverableKeyStoreSecondaryKey newSecondaryKey)
+            throws ActiveSecondaryNotInKeychainException, IOException,
+                    NoActiveSecondaryKeyException, IllegalBlockSizeException, InvalidKeyException,
+                    InternalRecoveryServiceException, UnrecoverableKeyException,
+                    InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+                    NoSuchPaddingException {
+        RecoverableKeyStoreSecondaryKey activeSecondaryKey = getActiveSecondaryKey();
+        String activeSecondaryKeyAlias = activeSecondaryKey.getAlias();
+        String newSecondaryKeyAlias = newSecondaryKey.getAlias();
+        if (newSecondaryKeyAlias.equals(activeSecondaryKeyAlias)) {
+            Slog.i(TAG, activeSecondaryKeyAlias + " was already the active alias.");
+            return;
+        }
+
+        TertiaryKeyStore tertiaryKeyStore =
+                TertiaryKeyStore.newInstance(mContext, activeSecondaryKey);
+        Map<String, SecretKey> tertiaryKeys = tertiaryKeyStore.getAll();
+
+        if (tertiaryKeys.isEmpty()) {
+            Slog.i(
+                    TAG,
+                    "No tertiary keys for " + activeSecondaryKeyAlias + ". No need to rewrap. ");
+            mBackupServer.setActiveSecondaryKeyAlias(
+                    newSecondaryKeyAlias, /*tertiaryKeys=*/ Collections.emptyMap());
+        } else {
+            Map<String, WrappedKeyProto.WrappedKey> rewrappedTertiaryKeys =
+                    rewrapAll(newSecondaryKey, tertiaryKeys);
+            TertiaryKeyStore.newInstance(mContext, newSecondaryKey).putAll(rewrappedTertiaryKeys);
+            Slog.i(
+                    TAG,
+                    "Successfully rewrapped " + rewrappedTertiaryKeys.size() + " tertiary keys");
+            mBackupServer.setActiveSecondaryKeyAlias(newSecondaryKeyAlias, rewrappedTertiaryKeys);
+            Slog.i(
+                    TAG,
+                    "Successfully uploaded new set of tertiary keys to "
+                            + newSecondaryKeyAlias
+                            + " alias");
+        }
+
+        mCryptoSettings.setActiveSecondaryKeyAlias(newSecondaryKeyAlias);
+        mCryptoSettings.removeNextSecondaryKeyAlias();
+        try {
+            mRecoveryController.removeKey(activeSecondaryKeyAlias);
+        } catch (InternalRecoveryServiceException e) {
+            Slog.e(TAG, "Error removing old secondary key from RecoverableKeyStoreLoader", e);
+        }
+    }
+
+    private RecoverableKeyStoreSecondaryKey getActiveSecondaryKey()
+            throws NoActiveSecondaryKeyException, ActiveSecondaryNotInKeychainException,
+                    InternalRecoveryServiceException, UnrecoverableKeyException {
+
+        Optional<String> activeSecondaryAlias = mCryptoSettings.getActiveSecondaryKeyAlias();
+
+        if (!activeSecondaryAlias.isPresent()) {
+            Slog.i(
+                    TAG,
+                    "Was asked to rotate secondary key, but local config did not have a secondary "
+                            + "key alias set.");
+            throw new NoActiveSecondaryKeyException("No local active secondary key set.");
+        }
+
+        String activeSecondaryKeyAlias = activeSecondaryAlias.get();
+        Optional<RecoverableKeyStoreSecondaryKey> secondaryKey =
+                mSecondaryKeyManager.get(activeSecondaryKeyAlias);
+
+        if (!secondaryKey.isPresent()) {
+            throw new ActiveSecondaryNotInKeychainException(
+                    String.format(
+                            Locale.US,
+                            "Had local active recoverable key alias of %s but key was not in"
+                                + " user's keychain.",
+                            activeSecondaryKeyAlias));
+        }
+
+        return secondaryKey.get();
+    }
+
+    /**
+     * Rewraps all the tertiary keys.
+     *
+     * @param newSecondaryKey The secondary key with which to rewrap the tertiaries.
+     * @param tertiaryKeys The tertiary keys, by package name.
+     * @return The newly wrapped tertiary keys, by package name.
+     * @throws InvalidKeyException if any key is unusable.
+     * @throws IllegalBlockSizeException if could not decrypt.
+     */
+    private Map<String, WrappedKeyProto.WrappedKey> rewrapAll(
+            RecoverableKeyStoreSecondaryKey newSecondaryKey, Map<String, SecretKey> tertiaryKeys)
+            throws InvalidKeyException, IllegalBlockSizeException, NoSuchPaddingException,
+                    NoSuchAlgorithmException {
+        Map<String, WrappedKeyProto.WrappedKey> wrappedKeys = new HashMap<>();
+
+        for (String packageName : tertiaryKeys.keySet()) {
+            SecretKey tertiaryKey = tertiaryKeys.get(packageName);
+            wrappedKeys.put(
+                    packageName, KeyWrapUtils.wrap(newSecondaryKey.getSecretKey(), tertiaryKey));
+        }
+
+        return wrappedKeys;
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/SizeQuotaExceededException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/SizeQuotaExceededException.java
new file mode 100644
index 0000000..515db86
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/SizeQuotaExceededException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.encryption.tasks;
+
+/** Exception thrown when aa backup has exceeded the space allowed for that user */
+public class SizeQuotaExceededException extends RuntimeException {
+    public SizeQuotaExceededException() {
+        super("Backup size quota exceeded.");
+    }
+}
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java
new file mode 100644
index 0000000..9a97e38
--- /dev/null
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/tasks/UnsupportedEncryptedFileException.java
@@ -0,0 +1,28 @@
+/*
+ * 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.encryption.tasks;
+
+/**
+ * Thrown when the backup file provided by the server uses encryption algorithms this version of
+ * backup does not support. This could happen if the backup was created with a newer version of the
+ * code.
+ */
+public class UnsupportedEncryptedFileException extends EncryptedRestoreException {
+    public UnsupportedEncryptedFileException(String message) {
+        super(message);
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric-integration/Android.bp b/packages/BackupEncryption/test/robolectric-integration/Android.bp
new file mode 100644
index 0000000..67365df
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric-integration/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_robolectric_test {
+    name: "BackupEncryptionRoboIntegTests",
+    srcs: [
+        "src/**/*.java",
+    ],
+    java_resource_dirs: ["config"],
+    libs: [
+        "backup-encryption-protos",
+        "platform-test-annotations",
+        "testng",
+        "truth-prebuilt",
+        "BackupEncryptionRoboTests",
+    ],
+    static_libs: [
+        "androidx.test.core",
+        "androidx.test.runner",
+        "androidx.test.rules",
+    ],
+    instrumentation_for: "BackupEncryption",
+}
diff --git a/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml b/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml
new file mode 100644
index 0000000..c3930cc
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric-integration/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          coreApp="true"
+          package="com.android.server.backup.encryption.robointeg">
+
+    <application/>
+
+</manifest>
diff --git a/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties b/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties
new file mode 100644
index 0000000..26fceb3
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric-integration/config/robolectric.properties
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+sdk=NEWEST_SDK
diff --git a/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java
new file mode 100644
index 0000000..a432d91
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric-integration/src/com/android/server/backup/encryption/RoundTripTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.security.keystore.recovery.InternalRecoveryServiceException;
+import android.security.keystore.recovery.RecoveryController;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.keys.KeyWrapUtils;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyRotationScheduler;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+import com.android.server.backup.encryption.tasks.EncryptedFullBackupTask;
+import com.android.server.backup.encryption.tasks.EncryptedFullRestoreTask;
+import com.android.server.backup.encryption.tasks.EncryptedKvBackupTask;
+import com.android.server.backup.encryption.tasks.EncryptedKvRestoreTask;
+import com.android.server.testing.shadows.DataEntity;
+import com.android.server.testing.shadows.ShadowBackupDataInput;
+import com.android.server.testing.shadows.ShadowBackupDataOutput;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Optional;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+
+@Config(
+        shadows = {
+            ShadowBackupDataInput.class,
+            ShadowBackupDataOutput.class,
+            ShadowRecoveryController.class
+        })
+@RunWith(RobolectricTestRunner.class)
+public class RoundTripTest {
+    private static final DataEntity[] KEY_VALUE_DATA = {
+        new DataEntity("test_key_1", "test_value_1"),
+        new DataEntity("test_key_2", "test_value_2"),
+        new DataEntity("test_key_3", "test_value_3")
+    };
+
+    /** Amount of data we want to round trip in this test */
+    private static final int TEST_DATA_SIZE = 1024 * 1024; // 1MB
+
+    /** Buffer size used when reading data from the restore task */
+    private static final int READ_BUFFER_SIZE = 1024; // 1024 byte buffer.
+
+    /** Key parameters used for the secondary encryption key */
+    private static final String KEY_ALGORITHM = "AES";
+
+    private static final int KEY_SIZE_BITS = 256;
+
+    /** Package name for our test package */
+    private static final String TEST_PACKAGE_NAME = "com.android.backup.test";
+
+    /** The name we use to refer to our secondary key */
+    private static final String TEST_KEY_ALIAS = "test/backup/KEY_ALIAS";
+
+    /** Original data used for comparison after round trip */
+    private final byte[] mOriginalData = new byte[TEST_DATA_SIZE];
+
+    /** App context, used to store the key data and chunk listings */
+    private Context mContext;
+
+    /** The secondary key we're using for the test */
+    private RecoverableKeyStoreSecondaryKey mSecondaryKey;
+
+    /** Source of random material which is considered non-predictable in its' generation */
+    private final SecureRandom mSecureRandom = new SecureRandom();
+
+    private RecoverableKeyStoreSecondaryKeyManager.RecoverableKeyStoreSecondaryKeyManagerProvider
+            mSecondaryKeyManagerProvider;
+    private DummyServer mDummyServer;
+    private RecoveryController mRecoveryController;
+
+    @Mock private ParcelFileDescriptor mParcelFileDescriptor;
+
+    @Before
+    public void setUp() throws NoSuchAlgorithmException, InternalRecoveryServiceException {
+        MockitoAnnotations.initMocks(this);
+
+        ShadowBackupDataInput.reset();
+        ShadowBackupDataOutput.reset();
+
+        mContext = ApplicationProvider.getApplicationContext();
+        mSecondaryKey = new RecoverableKeyStoreSecondaryKey(TEST_KEY_ALIAS, generateAesKey());
+        mDummyServer = new DummyServer();
+        mSecondaryKeyManagerProvider =
+                () ->
+                        new RecoverableKeyStoreSecondaryKeyManager(
+                                RecoveryController.getInstance(mContext), mSecureRandom);
+
+        fillBuffer(mOriginalData);
+    }
+
+    @Test
+    public void testFull_nonIncrementalBackupAndRestoreAreSuccessful() throws Exception {
+        byte[] backupData = performFullBackup(mOriginalData);
+        assertThat(backupData).isNotEqualTo(mOriginalData);
+        byte[] restoredData = performFullRestore(backupData);
+        assertThat(restoredData).isEqualTo(mOriginalData);
+    }
+
+    @Test
+    public void testKeyValue_nonIncrementalBackupAndRestoreAreSuccessful() throws Exception {
+        byte[] backupData = performNonIncrementalKeyValueBackup(KEY_VALUE_DATA);
+
+        // Get the secondary key used to do backup.
+        Optional<RecoverableKeyStoreSecondaryKey> secondaryKey =
+                mSecondaryKeyManagerProvider.get().get(mDummyServer.mSecondaryKeyAlias);
+        assertThat(secondaryKey.isPresent()).isTrue();
+
+        Set<DataEntity> restoredData = performKeyValueRestore(backupData, secondaryKey.get());
+
+        assertThat(restoredData).containsExactly(KEY_VALUE_DATA).inOrder();
+    }
+
+    /** Perform a key/value backup and return the backed-up representation of the data */
+    private byte[] performNonIncrementalKeyValueBackup(DataEntity[] backupData)
+            throws Exception {
+        // Populate test key/value data.
+        for (DataEntity entity : backupData) {
+            ShadowBackupDataInput.addEntity(entity);
+        }
+
+        EncryptedKvBackupTask.EncryptedKvBackupTaskFactory backupTaskFactory =
+                new EncryptedKvBackupTask.EncryptedKvBackupTaskFactory();
+        EncryptedKvBackupTask backupTask =
+                backupTaskFactory.newInstance(
+                        mContext,
+                        mSecureRandom,
+                        mDummyServer,
+                        CryptoSettings.getInstance(mContext),
+                        mSecondaryKeyManagerProvider,
+                        mParcelFileDescriptor,
+                        TEST_PACKAGE_NAME);
+
+        backupTask.performBackup(/* incremental */ false);
+
+        return mDummyServer.mStoredData;
+    }
+
+    /** Perform a full backup and return the backed-up representation of the data */
+    private byte[] performFullBackup(byte[] backupData) throws Exception {
+        DummyServer dummyServer = new DummyServer();
+        EncryptedFullBackupTask backupTask =
+                EncryptedFullBackupTask.newInstance(
+                        mContext,
+                        dummyServer,
+                        mSecureRandom,
+                        mSecondaryKey,
+                        TEST_PACKAGE_NAME,
+                        new ByteArrayInputStream(backupData));
+        backupTask.call();
+        return dummyServer.mStoredData;
+    }
+
+    private Set<DataEntity> performKeyValueRestore(
+            byte[] backupData, RecoverableKeyStoreSecondaryKey secondaryKey) throws Exception {
+        EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory restoreTaskFactory =
+                new EncryptedKvRestoreTask.EncryptedKvRestoreTaskFactory();
+        EncryptedKvRestoreTask restoreTask =
+                restoreTaskFactory.newInstance(
+                        mContext,
+                        mSecondaryKeyManagerProvider,
+                        new FakeFullRestoreDownloader(backupData),
+                        secondaryKey.getAlias(),
+                        KeyWrapUtils.wrap(
+                                secondaryKey.getSecretKey(), getTertiaryKey(secondaryKey)));
+        restoreTask.getRestoreData(mParcelFileDescriptor);
+        return ShadowBackupDataOutput.getEntities();
+    }
+
+    /** Perform a full restore and return the bytes obtained from the restore process */
+    private byte[] performFullRestore(byte[] backupData)
+            throws IOException, NoSuchAlgorithmException, NoSuchPaddingException,
+                    InvalidAlgorithmParameterException, InvalidKeyException,
+                    IllegalBlockSizeException {
+        ByteArrayOutputStream decryptedOutput = new ByteArrayOutputStream();
+
+        EncryptedFullRestoreTask restoreTask =
+                EncryptedFullRestoreTask.newInstance(
+                        mContext,
+                        new FakeFullRestoreDownloader(backupData),
+                        getTertiaryKey(mSecondaryKey));
+
+        byte[] buffer = new byte[READ_BUFFER_SIZE];
+        int bytesRead = restoreTask.readNextChunk(buffer);
+        while (bytesRead != -1) {
+            decryptedOutput.write(buffer, 0, bytesRead);
+            bytesRead = restoreTask.readNextChunk(buffer);
+        }
+
+        return decryptedOutput.toByteArray();
+    }
+
+    /** Get the tertiary key for our test package from the key manager */
+    private SecretKey getTertiaryKey(RecoverableKeyStoreSecondaryKey secondaryKey)
+            throws IllegalBlockSizeException, InvalidAlgorithmParameterException,
+                    NoSuchAlgorithmException, IOException, NoSuchPaddingException,
+                    InvalidKeyException {
+        TertiaryKeyManager tertiaryKeyManager =
+                new TertiaryKeyManager(
+                        mContext,
+                        mSecureRandom,
+                        TertiaryKeyRotationScheduler.getInstance(mContext),
+                        secondaryKey,
+                        TEST_PACKAGE_NAME);
+        return tertiaryKeyManager.getKey();
+    }
+
+    /** Fill a buffer with data in a predictable way */
+    private void fillBuffer(byte[] buffer) {
+        byte loopingCounter = 0;
+        for (int i = 0; i < buffer.length; i++) {
+            buffer[i] = loopingCounter;
+            loopingCounter++;
+        }
+    }
+
+    /** Generate a new, random, AES key */
+    public static SecretKey generateAesKey() throws NoSuchAlgorithmException {
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+        keyGenerator.init(KEY_SIZE_BITS);
+        return keyGenerator.generateKey();
+    }
+
+    /**
+     * Dummy backup data endpoint. This stores the data so we can use it in subsequent test steps.
+     */
+    private static class DummyServer implements CryptoBackupServer {
+        private static final String DUMMY_DOC_ID = "DummyDoc";
+
+        byte[] mStoredData = null;
+        String mSecondaryKeyAlias;
+
+        @Override
+        public String uploadIncrementalBackup(
+                String packageName,
+                String oldDocId,
+                byte[] diffScript,
+                WrappedKeyProto.WrappedKey tertiaryKey) {
+            throw new RuntimeException("Not Implemented");
+        }
+
+        @Override
+        public String uploadNonIncrementalBackup(
+                String packageName, byte[] data, WrappedKeyProto.WrappedKey tertiaryKey) {
+            assertThat(packageName).isEqualTo(TEST_PACKAGE_NAME);
+            mStoredData = data;
+            return DUMMY_DOC_ID;
+        }
+
+        @Override
+        public void setActiveSecondaryKeyAlias(
+                String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) {
+            mSecondaryKeyAlias = keyAlias;
+        }
+    }
+
+    /** Fake package wrapper which returns data from a byte array. */
+    private static class FakeFullRestoreDownloader extends FullRestoreDownloader {
+        private final ByteArrayInputStream mData;
+
+        FakeFullRestoreDownloader(byte[] data) {
+            // We override all methods of the superclass, so it does not require any collaborators.
+            super();
+            mData = new ByteArrayInputStream(data);
+        }
+
+        @Override
+        public int readNextChunk(byte[] buffer) throws IOException {
+            return mData.read(buffer);
+        }
+
+        @Override
+        public void finish(FinishType finishType) {
+            // Do nothing.
+        }
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java
new file mode 100644
index 0000000..07a6fd2
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/BackupFileDecryptorTaskTest.java
@@ -0,0 +1,583 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.android.server.backup.testing.CryptoTestUtils.generateAesKey;
+import static com.android.server.backup.testing.CryptoTestUtils.newChunkOrdering;
+import static com.android.server.backup.testing.CryptoTestUtils.newChunksMetadata;
+import static com.android.server.backup.testing.CryptoTestUtils.newPair;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+import static org.testng.Assert.expectThrows;
+
+import android.annotation.Nullable;
+import android.app.backup.BackupDataInput;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.ChunkHasher;
+import com.android.server.backup.encryption.chunking.DecryptedChunkFileOutput;
+import com.android.server.backup.encryption.chunking.EncryptedChunk;
+import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer;
+import com.android.server.backup.encryption.kv.DecryptedChunkKvOutput;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkOrdering;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunksMetadata;
+import com.android.server.backup.encryption.protos.nano.KeyValuePairProto.KeyValuePair;
+import com.android.server.backup.encryption.tasks.BackupEncrypter.Result;
+import com.android.server.backup.testing.CryptoTestUtils;
+import com.android.server.testing.shadows.ShadowBackupDataInput;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.protobuf.nano.MessageNano;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.RandomAccessFile;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import javax.crypto.AEADBadTagException;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+@Config(shadows = {ShadowBackupDataInput.class})
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class BackupFileDecryptorTaskTest {
+    private static final String READ_WRITE_MODE = "rw";
+    private static final int BYTES_PER_KILOBYTE = 1024;
+    private static final int MIN_CHUNK_SIZE_BYTES = 2 * BYTES_PER_KILOBYTE;
+    private static final int AVERAGE_CHUNK_SIZE_BYTES = 4 * BYTES_PER_KILOBYTE;
+    private static final int MAX_CHUNK_SIZE_BYTES = 64 * BYTES_PER_KILOBYTE;
+    private static final int BACKUP_DATA_SIZE_BYTES = 60 * BYTES_PER_KILOBYTE;
+    private static final int GCM_NONCE_LENGTH_BYTES = 12;
+    private static final int GCM_TAG_LENGTH_BYTES = 16;
+    private static final int BITS_PER_BYTE = 8;
+    private static final int CHECKSUM_LENGTH_BYTES = 256 / BITS_PER_BYTE;
+    @Nullable private static final FileDescriptor NULL_FILE_DESCRIPTOR = null;
+
+    private static final Set<KeyValuePair> TEST_KV_DATA = new HashSet<>();
+
+    static {
+        TEST_KV_DATA.add(newPair("key1", "value1"));
+        TEST_KV_DATA.add(newPair("key2", "value2"));
+    }
+
+    @Rule public final TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    private SecretKey mTertiaryKey;
+    private SecretKey mChunkEncryptionKey;
+    private File mInputFile;
+    private File mOutputFile;
+    private DecryptedChunkOutput mFileOutput;
+    private DecryptedChunkKvOutput mKvOutput;
+    private Random mRandom;
+    private BackupFileDecryptorTask mTask;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mRandom = new Random();
+        mTertiaryKey = generateAesKey();
+        // In good situations it's always the same. We allow changing it for testing when somehow it
+        // has become mismatched that we throw an error.
+        mChunkEncryptionKey = mTertiaryKey;
+        mInputFile = mTemporaryFolder.newFile();
+        mOutputFile = mTemporaryFolder.newFile();
+        mFileOutput = new DecryptedChunkFileOutput(mOutputFile);
+        mKvOutput = new DecryptedChunkKvOutput(new ChunkHasher(mTertiaryKey));
+        mTask = new BackupFileDecryptorTask(mTertiaryKey);
+    }
+
+    @Test
+    public void decryptFile_throwsForNonExistentInput() throws Exception {
+        assertThrows(
+                FileNotFoundException.class,
+                () ->
+                        mTask.decryptFile(
+                                new File(mTemporaryFolder.newFolder(), "nonexistent"),
+                                mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForDirectoryInputFile() throws Exception {
+        assertThrows(
+                FileNotFoundException.class,
+                () -> mTask.decryptFile(mTemporaryFolder.newFolder(), mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_withExplicitStarts_decryptsEncryptedData() throws Exception {
+        byte[] backupData = randomData(BACKUP_DATA_SIZE_BYTES);
+        createEncryptedFileUsingExplicitStarts(backupData);
+
+        mTask.decryptFile(mInputFile, mFileOutput);
+
+        assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData);
+    }
+
+    @Test
+    public void decryptFile_withInlineLengths_decryptsEncryptedData() throws Exception {
+        createEncryptedFileUsingInlineLengths(
+                TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata);
+        mTask.decryptFile(mInputFile, mKvOutput);
+        assertThat(asMap(mKvOutput.getPairs())).containsExactlyEntriesIn(asMap(TEST_KV_DATA));
+    }
+
+    @Test
+    public void decryptFile_withNoChunkOrderingType_decryptsUsingExplicitStarts() throws Exception {
+        byte[] backupData = randomData(BACKUP_DATA_SIZE_BYTES);
+        createEncryptedFileUsingExplicitStarts(
+                backupData,
+                chunkOrdering -> chunkOrdering,
+                chunksMetadata -> {
+                    ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata);
+                    metadata.chunkOrderingType =
+                            ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED;
+                    return metadata;
+                });
+
+        mTask.decryptFile(mInputFile, mFileOutput);
+
+        assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData);
+    }
+
+    @Test
+    public void decryptFile_withInlineLengths_throwsForZeroLengths() throws Exception {
+        createEncryptedFileUsingInlineLengths(
+                TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata);
+
+        // Set the length of the first chunk to zero.
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(0);
+        raf.writeInt(0);
+
+        assertThrows(
+                MalformedEncryptedFileException.class,
+                () -> mTask.decryptFile(mInputFile, mKvOutput));
+    }
+
+    @Test
+    public void decryptFile_withInlineLengths_throwsForLongLengths() throws Exception {
+        createEncryptedFileUsingInlineLengths(
+                TEST_KV_DATA, chunkOrdering -> chunkOrdering, chunksMetadata -> chunksMetadata);
+
+        // Set the length of the first chunk to zero.
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(0);
+        raf.writeInt((int) mInputFile.length());
+
+        assertThrows(
+                MalformedEncryptedFileException.class,
+                () -> mTask.decryptFile(mInputFile, mKvOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForBadKey() throws Exception {
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        assertThrows(
+                AEADBadTagException.class,
+                () ->
+                        new BackupFileDecryptorTask(generateAesKey())
+                                .decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_withExplicitStarts_throwsForMangledOrdering() throws Exception {
+        createEncryptedFileUsingExplicitStarts(
+                randomData(BACKUP_DATA_SIZE_BYTES),
+                chunkOrdering -> {
+                    ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering);
+                    Arrays.sort(ordering.starts);
+                    return ordering;
+                });
+
+        assertThrows(
+                MessageDigestMismatchException.class,
+                () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_withExplicitStarts_noChunks_returnsNoData() throws Exception {
+        byte[] backupData = randomData(/*length=*/ 0);
+        createEncryptedFileUsingExplicitStarts(
+                backupData,
+                chunkOrdering -> {
+                    ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering);
+                    ordering.starts = new int[0];
+                    return ordering;
+                });
+
+        mTask.decryptFile(mInputFile, mFileOutput);
+
+        assertThat(Files.readAllBytes(Paths.get(mOutputFile.toURI()))).isEqualTo(backupData);
+    }
+
+    @Test
+    public void decryptFile_throwsForMismatchedChecksum() throws Exception {
+        createEncryptedFileUsingExplicitStarts(
+                randomData(BACKUP_DATA_SIZE_BYTES),
+                chunkOrdering -> {
+                    ChunkOrdering ordering = CryptoTestUtils.clone(chunkOrdering);
+                    ordering.checksum =
+                            Arrays.copyOf(randomData(CHECKSUM_LENGTH_BYTES), CHECKSUM_LENGTH_BYTES);
+                    return ordering;
+                });
+
+        assertThrows(
+                MessageDigestMismatchException.class,
+                () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForBadChunksMetadataOffset() throws Exception {
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        // Replace the metadata with all 1s.
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(raf.length() - Long.BYTES);
+        int metadataOffset = (int) raf.readLong();
+        int metadataLength = (int) raf.length() - metadataOffset - Long.BYTES;
+
+        byte[] allOnes = new byte[metadataLength];
+        Arrays.fill(allOnes, (byte) 1);
+
+        raf.seek(metadataOffset);
+        raf.write(allOnes, /*off=*/ 0, metadataLength);
+
+        MalformedEncryptedFileException thrown =
+                expectThrows(
+                        MalformedEncryptedFileException.class,
+                        () -> mTask.decryptFile(mInputFile, mFileOutput));
+        assertThat(thrown)
+                .hasMessageThat()
+                .isEqualTo(
+                        "Could not read chunks metadata at position "
+                                + metadataOffset
+                                + " of file of "
+                                + raf.length()
+                                + " bytes");
+    }
+
+    @Test
+    public void decryptFile_throwsForChunksMetadataOffsetBeyondEndOfFile() throws Exception {
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(raf.length() - Long.BYTES);
+        raf.writeLong(raf.length());
+
+        MalformedEncryptedFileException thrown =
+                expectThrows(
+                        MalformedEncryptedFileException.class,
+                        () -> mTask.decryptFile(mInputFile, mFileOutput));
+        assertThat(thrown)
+                .hasMessageThat()
+                .isEqualTo(
+                        raf.length()
+                                + " is not valid position for chunks metadata in file of "
+                                + raf.length()
+                                + " bytes");
+    }
+
+    @Test
+    public void decryptFile_throwsForChunksMetadataOffsetBeforeBeginningOfFile() throws Exception {
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(raf.length() - Long.BYTES);
+        raf.writeLong(-1);
+
+        MalformedEncryptedFileException thrown =
+                expectThrows(
+                        MalformedEncryptedFileException.class,
+                        () -> mTask.decryptFile(mInputFile, mFileOutput));
+        assertThat(thrown)
+                .hasMessageThat()
+                .isEqualTo(
+                        "-1 is not valid position for chunks metadata in file of "
+                                + raf.length()
+                                + " bytes");
+    }
+
+    @Test
+    public void decryptFile_throwsForMangledChunks() throws Exception {
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        // Mess up some bits in a random byte
+        RandomAccessFile raf = new RandomAccessFile(mInputFile, READ_WRITE_MODE);
+        raf.seek(50);
+        byte fiftiethByte = raf.readByte();
+        raf.seek(50);
+        raf.write(~fiftiethByte);
+
+        assertThrows(AEADBadTagException.class, () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForBadChunkEncryptionKey() throws Exception {
+        mChunkEncryptionKey = generateAesKey();
+
+        createEncryptedFileUsingExplicitStarts(randomData(BACKUP_DATA_SIZE_BYTES));
+
+        assertThrows(AEADBadTagException.class, () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForUnsupportedCipherType() throws Exception {
+        createEncryptedFileUsingExplicitStarts(
+                randomData(BACKUP_DATA_SIZE_BYTES),
+                chunkOrdering -> chunkOrdering,
+                chunksMetadata -> {
+                    ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata);
+                    metadata.cipherType = ChunksMetadataProto.UNKNOWN_CIPHER_TYPE;
+                    return metadata;
+                });
+
+        assertThrows(
+                UnsupportedEncryptedFileException.class,
+                () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    @Test
+    public void decryptFile_throwsForUnsupportedMessageDigestType() throws Exception {
+        createEncryptedFileUsingExplicitStarts(
+                randomData(BACKUP_DATA_SIZE_BYTES),
+                chunkOrdering -> chunkOrdering,
+                chunksMetadata -> {
+                    ChunksMetadata metadata = CryptoTestUtils.clone(chunksMetadata);
+                    metadata.checksumType = ChunksMetadataProto.UNKNOWN_CHECKSUM_TYPE;
+                    return metadata;
+                });
+
+        assertThrows(
+                UnsupportedEncryptedFileException.class,
+                () -> mTask.decryptFile(mInputFile, mFileOutput));
+    }
+
+    /**
+     * Creates an encrypted backup file from the given data.
+     *
+     * @param data The plaintext content.
+     */
+    private void createEncryptedFileUsingExplicitStarts(byte[] data) throws Exception {
+        createEncryptedFileUsingExplicitStarts(data, chunkOrdering -> chunkOrdering);
+    }
+
+    /**
+     * Creates an encrypted backup file from the given data.
+     *
+     * @param data The plaintext content.
+     * @param chunkOrderingTransformer Transforms the ordering before it's encrypted.
+     */
+    private void createEncryptedFileUsingExplicitStarts(
+            byte[] data, Transformer<ChunkOrdering> chunkOrderingTransformer) throws Exception {
+        createEncryptedFileUsingExplicitStarts(
+                data, chunkOrderingTransformer, chunksMetadata -> chunksMetadata);
+    }
+
+    /**
+     * Creates an encrypted backup file from the given data in mode {@link
+     * ChunksMetadataProto#EXPLICIT_STARTS}.
+     *
+     * @param data The plaintext content.
+     * @param chunkOrderingTransformer Transforms the ordering before it's encrypted.
+     * @param chunksMetadataTransformer Transforms the metadata before it's written.
+     */
+    private void createEncryptedFileUsingExplicitStarts(
+            byte[] data,
+            Transformer<ChunkOrdering> chunkOrderingTransformer,
+            Transformer<ChunksMetadata> chunksMetadataTransformer)
+            throws Exception {
+        Result result = backupFullData(data);
+
+        ArrayList<EncryptedChunk> chunks = new ArrayList<>(result.getNewChunks());
+        Collections.shuffle(chunks);
+        HashMap<ChunkHash, Integer> startPositions = new HashMap<>();
+
+        try (FileOutputStream fos = new FileOutputStream(mInputFile);
+                DataOutputStream dos = new DataOutputStream(fos)) {
+            int position = 0;
+
+            for (EncryptedChunk chunk : chunks) {
+                startPositions.put(chunk.key(), position);
+                dos.write(chunk.nonce());
+                dos.write(chunk.encryptedBytes());
+                position += chunk.nonce().length + chunk.encryptedBytes().length;
+            }
+
+            int[] starts = new int[chunks.size()];
+            List<ChunkHash> chunkListing = result.getAllChunks();
+
+            for (int i = 0; i < chunks.size(); i++) {
+                starts[i] = startPositions.get(chunkListing.get(i));
+            }
+
+            ChunkOrdering chunkOrdering = newChunkOrdering(starts, result.getDigest());
+            chunkOrdering = chunkOrderingTransformer.accept(chunkOrdering);
+
+            ChunksMetadata metadata =
+                    newChunksMetadata(
+                            ChunksMetadataProto.AES_256_GCM,
+                            ChunksMetadataProto.SHA_256,
+                            ChunksMetadataProto.EXPLICIT_STARTS,
+                            encrypt(chunkOrdering));
+            metadata = chunksMetadataTransformer.accept(metadata);
+
+            dos.write(MessageNano.toByteArray(metadata));
+            dos.writeLong(position);
+        }
+    }
+
+    /**
+     * Creates an encrypted backup file from the given data in mode {@link
+     * ChunksMetadataProto#INLINE_LENGTHS}.
+     *
+     * @param data The plaintext key value pairs to back up.
+     * @param chunkOrderingTransformer Transforms the ordering before it's encrypted.
+     * @param chunksMetadataTransformer Transforms the metadata before it's written.
+     */
+    private void createEncryptedFileUsingInlineLengths(
+            Set<KeyValuePair> data,
+            Transformer<ChunkOrdering> chunkOrderingTransformer,
+            Transformer<ChunksMetadata> chunksMetadataTransformer)
+            throws Exception {
+        Result result = backupKvData(data);
+
+        List<EncryptedChunk> chunks = new ArrayList<>(result.getNewChunks());
+        System.out.println("we have chunk count " + chunks.size());
+        Collections.shuffle(chunks);
+
+        try (FileOutputStream fos = new FileOutputStream(mInputFile);
+                DataOutputStream dos = new DataOutputStream(fos)) {
+            for (EncryptedChunk chunk : chunks) {
+                dos.writeInt(chunk.nonce().length + chunk.encryptedBytes().length);
+                dos.write(chunk.nonce());
+                dos.write(chunk.encryptedBytes());
+            }
+
+            ChunkOrdering chunkOrdering = newChunkOrdering(null, result.getDigest());
+            chunkOrdering = chunkOrderingTransformer.accept(chunkOrdering);
+
+            ChunksMetadata metadata =
+                    newChunksMetadata(
+                            ChunksMetadataProto.AES_256_GCM,
+                            ChunksMetadataProto.SHA_256,
+                            ChunksMetadataProto.INLINE_LENGTHS,
+                            encrypt(chunkOrdering));
+            metadata = chunksMetadataTransformer.accept(metadata);
+
+            int metadataStart = dos.size();
+            dos.write(MessageNano.toByteArray(metadata));
+            dos.writeLong(metadataStart);
+        }
+    }
+
+    /** Performs a full backup of the given data, and returns the chunks. */
+    private BackupEncrypter.Result backupFullData(byte[] data) throws Exception {
+        BackupStreamEncrypter encrypter =
+                new BackupStreamEncrypter(
+                        new ByteArrayInputStream(data),
+                        MIN_CHUNK_SIZE_BYTES,
+                        MAX_CHUNK_SIZE_BYTES,
+                        AVERAGE_CHUNK_SIZE_BYTES);
+        return encrypter.backup(
+                mChunkEncryptionKey,
+                randomData(FingerprintMixer.SALT_LENGTH_BYTES),
+                new HashSet<>());
+    }
+
+    private Result backupKvData(Set<KeyValuePair> data) throws Exception {
+        ShadowBackupDataInput.reset();
+        for (KeyValuePair pair : data) {
+            ShadowBackupDataInput.addEntity(pair.key, pair.value);
+        }
+        KvBackupEncrypter encrypter =
+                new KvBackupEncrypter(new BackupDataInput(NULL_FILE_DESCRIPTOR));
+        return encrypter.backup(
+                mChunkEncryptionKey,
+                randomData(FingerprintMixer.SALT_LENGTH_BYTES),
+                Collections.EMPTY_SET);
+    }
+
+    /** Encrypts {@code chunkOrdering} using {@link #mTertiaryKey}. */
+    private byte[] encrypt(ChunkOrdering chunkOrdering) throws Exception {
+        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+        byte[] nonce = randomData(GCM_NONCE_LENGTH_BYTES);
+        cipher.init(
+                Cipher.ENCRYPT_MODE,
+                mTertiaryKey,
+                new GCMParameterSpec(GCM_TAG_LENGTH_BYTES * BITS_PER_BYTE, nonce));
+        byte[] nanoBytes = MessageNano.toByteArray(chunkOrdering);
+        byte[] encryptedBytes = cipher.doFinal(nanoBytes);
+
+        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
+            out.write(nonce);
+            out.write(encryptedBytes);
+            return out.toByteArray();
+        }
+    }
+
+    /** Returns {@code length} random bytes. */
+    private byte[] randomData(int length) {
+        byte[] data = new byte[length];
+        mRandom.nextBytes(data);
+        return data;
+    }
+
+    private static ImmutableMap<String, String> asMap(Collection<KeyValuePair> pairs) {
+        ImmutableMap.Builder<String, String> map = ImmutableMap.builder();
+        for (KeyValuePair pair : pairs) {
+            map.put(pair.key, new String(pair.value, Charset.forName("UTF-8")));
+        }
+        return map.build();
+    }
+
+    private interface Transformer<T> {
+        T accept(T t);
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java
new file mode 100644
index 0000000..096b2da
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java
@@ -0,0 +1,234 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto.ChunkListing;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto.WrappedKey;
+import com.android.server.backup.testing.CryptoTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Optional;
+
+import javax.crypto.SecretKey;
+
+@Config(shadows = {EncryptedBackupTaskTest.ShadowBackupFileBuilder.class})
+@RunWith(RobolectricTestRunner.class)
+public class EncryptedFullBackupTaskTest {
+    private static final String TEST_PACKAGE_NAME = "com.example.package";
+    private static final byte[] TEST_EXISTING_FINGERPRINT_MIXER_SALT =
+            Arrays.copyOf(new byte[] {11}, ChunkHash.HASH_LENGTH_BYTES);
+    private static final byte[] TEST_GENERATED_FINGERPRINT_MIXER_SALT =
+            Arrays.copyOf(new byte[] {22}, ChunkHash.HASH_LENGTH_BYTES);
+    private static final ChunkHash TEST_CHUNK_HASH_1 =
+            new ChunkHash(Arrays.copyOf(new byte[] {1}, ChunkHash.HASH_LENGTH_BYTES));
+    private static final ChunkHash TEST_CHUNK_HASH_2 =
+            new ChunkHash(Arrays.copyOf(new byte[] {2}, ChunkHash.HASH_LENGTH_BYTES));
+    private static final int TEST_CHUNK_LENGTH_1 = 20;
+    private static final int TEST_CHUNK_LENGTH_2 = 40;
+
+    @Mock private ProtoStore<ChunkListing> mChunkListingStore;
+    @Mock private TertiaryKeyManager mTertiaryKeyManager;
+    @Mock private InputStream mInputStream;
+    @Mock private EncryptedBackupTask mEncryptedBackupTask;
+    @Mock private SecretKey mTertiaryKey;
+    @Mock private SecureRandom mSecureRandom;
+
+    private EncryptedFullBackupTask mTask;
+    private ChunkListing mOldChunkListing;
+    private ChunkListing mNewChunkListing;
+    private WrappedKey mWrappedTertiaryKey;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mWrappedTertiaryKey = new WrappedKey();
+        when(mTertiaryKeyManager.getKey()).thenReturn(mTertiaryKey);
+        when(mTertiaryKeyManager.getWrappedKey()).thenReturn(mWrappedTertiaryKey);
+
+        mOldChunkListing =
+                CryptoTestUtils.newChunkListing(
+                        /* docId */ null,
+                        TEST_EXISTING_FINGERPRINT_MIXER_SALT,
+                        ChunksMetadataProto.AES_256_GCM,
+                        ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED,
+                        CryptoTestUtils.newChunk(TEST_CHUNK_HASH_1.getHash(), TEST_CHUNK_LENGTH_1));
+        mNewChunkListing =
+                CryptoTestUtils.newChunkListing(
+                        /* docId */ null,
+                        /* fingerprintSalt */ null,
+                        ChunksMetadataProto.AES_256_GCM,
+                        ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED,
+                        CryptoTestUtils.newChunk(TEST_CHUNK_HASH_1.getHash(), TEST_CHUNK_LENGTH_1),
+                        CryptoTestUtils.newChunk(TEST_CHUNK_HASH_2.getHash(), TEST_CHUNK_LENGTH_2));
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenReturn(mNewChunkListing);
+        when(mEncryptedBackupTask.performIncrementalBackup(any(), any(), any()))
+                .thenReturn(mNewChunkListing);
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty());
+
+        doAnswer(invocation -> {
+            byte[] byteArray = (byte[]) invocation.getArguments()[0];
+            System.arraycopy(
+                    TEST_GENERATED_FINGERPRINT_MIXER_SALT,
+                    /* srcPos */ 0,
+                    byteArray,
+                    /* destPos */ 0,
+                    FingerprintMixer.SALT_LENGTH_BYTES);
+            return null;
+        })
+                .when(mSecureRandom)
+                .nextBytes(any(byte[].class));
+
+        mTask =
+                new EncryptedFullBackupTask(
+                        mChunkListingStore,
+                        mTertiaryKeyManager,
+                        mEncryptedBackupTask,
+                        mInputStream,
+                        TEST_PACKAGE_NAME,
+                        mSecureRandom);
+    }
+
+    @Test
+    public void call_existingChunkListingButTertiaryKeyRotated_performsNonIncrementalBackup()
+            throws Exception {
+        when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true);
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME))
+                .thenReturn(Optional.of(mOldChunkListing));
+
+        mTask.call();
+
+        verify(mEncryptedBackupTask)
+                .performNonIncrementalBackup(
+                        eq(mTertiaryKey),
+                        eq(mWrappedTertiaryKey),
+                        eq(TEST_GENERATED_FINGERPRINT_MIXER_SALT));
+    }
+
+    @Test
+    public void call_noExistingChunkListing_performsNonIncrementalBackup() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty());
+        mTask.call();
+        verify(mEncryptedBackupTask)
+                .performNonIncrementalBackup(
+                        eq(mTertiaryKey),
+                        eq(mWrappedTertiaryKey),
+                        eq(TEST_GENERATED_FINGERPRINT_MIXER_SALT));
+    }
+
+    @Test
+    public void call_existingChunkListing_performsIncrementalBackup() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME))
+                .thenReturn(Optional.of(mOldChunkListing));
+        mTask.call();
+        verify(mEncryptedBackupTask)
+                .performIncrementalBackup(
+                        eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(mOldChunkListing));
+    }
+
+    @Test
+    public void
+            call_existingChunkListingWithNoFingerprintMixerSalt_doesntSetSaltBeforeIncBackup()
+                    throws Exception {
+        mOldChunkListing.fingerprintMixerSalt = new byte[0];
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME))
+                .thenReturn(Optional.of(mOldChunkListing));
+
+        mTask.call();
+
+        verify(mEncryptedBackupTask)
+                .performIncrementalBackup(
+                        eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(mOldChunkListing));
+    }
+
+    @Test
+    public void call_noExistingChunkListing_storesNewChunkListing() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty());
+        mTask.call();
+        verify(mChunkListingStore).saveProto(TEST_PACKAGE_NAME, mNewChunkListing);
+    }
+
+    @Test
+    public void call_existingChunkListing_storesNewChunkListing() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME))
+                .thenReturn(Optional.of(mOldChunkListing));
+        mTask.call();
+        verify(mChunkListingStore).saveProto(TEST_PACKAGE_NAME, mNewChunkListing);
+    }
+
+    @Test
+    public void call_exceptionDuringBackup_doesNotSaveNewChunkListing() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME)).thenReturn(Optional.empty());
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenThrow(GeneralSecurityException.class);
+
+        assertThrows(Exception.class, () -> mTask.call());
+
+        assertThat(mChunkListingStore.loadProto(TEST_PACKAGE_NAME).isPresent()).isFalse();
+    }
+
+    @Test
+    public void call_incrementalThrowsPermanentException_clearsState() throws Exception {
+        when(mChunkListingStore.loadProto(TEST_PACKAGE_NAME))
+                .thenReturn(Optional.of(mOldChunkListing));
+        when(mEncryptedBackupTask.performIncrementalBackup(any(), any(), any()))
+                .thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> mTask.call());
+
+        verify(mChunkListingStore).deleteProto(TEST_PACKAGE_NAME);
+    }
+
+    @Test
+    public void call_closesInputStream() throws Exception {
+        mTask.call();
+        verify(mInputStream).close();
+    }
+
+    @Test
+    public void cancel_cancelsTask() throws Exception {
+        mTask.cancel();
+        verify(mEncryptedBackupTask).cancel();
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java
new file mode 100644
index 0000000..0affacd
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullRestoreTaskTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+
+import static java.util.stream.Collectors.toList;
+
+import com.android.server.backup.encryption.FullRestoreDownloader;
+
+import com.google.common.io.Files;
+import com.google.common.primitives.Bytes;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+
+@RunWith(RobolectricTestRunner.class)
+public class EncryptedFullRestoreTaskTest {
+    private static final int TEST_BUFFER_SIZE = 10;
+    private static final byte[] TEST_ENCRYPTED_DATA = {1, 2, 3, 4, 5, 6};
+    private static final byte[] TEST_DECRYPTED_DATA = fakeDecrypt(TEST_ENCRYPTED_DATA);
+
+    @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+    @Mock private BackupFileDecryptorTask mDecryptorTask;
+
+    private File mFolder;
+    private FakeFullRestoreDownloader mFullRestorePackageWrapper;
+    private EncryptedFullRestoreTask mTask;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mFolder = temporaryFolder.newFolder();
+        mFullRestorePackageWrapper = new FakeFullRestoreDownloader(TEST_ENCRYPTED_DATA);
+
+        doAnswer(
+            invocation -> {
+                File source = invocation.getArgument(0);
+                DecryptedChunkOutput target = invocation.getArgument(1);
+                byte[] decrypted = fakeDecrypt(Files.toByteArray(source));
+                target.open();
+                target.processChunk(decrypted, decrypted.length);
+                target.close();
+                return null;
+            })
+                .when(mDecryptorTask)
+                .decryptFile(any(), any());
+
+        mTask = new EncryptedFullRestoreTask(mFolder, mFullRestorePackageWrapper, mDecryptorTask);
+    }
+
+    @Test
+    public void readNextChunk_downloadsAndDecryptsBackup() throws Exception {
+        ByteArrayOutputStream decryptedOutput = new ByteArrayOutputStream();
+
+        byte[] buffer = new byte[TEST_BUFFER_SIZE];
+        int bytesRead = mTask.readNextChunk(buffer);
+        while (bytesRead != -1) {
+            decryptedOutput.write(buffer, 0, bytesRead);
+            bytesRead = mTask.readNextChunk(buffer);
+        }
+
+        assertThat(decryptedOutput.toByteArray()).isEqualTo(TEST_DECRYPTED_DATA);
+    }
+
+    @Test
+    public void finish_deletesTemporaryFiles() throws Exception {
+        mTask.readNextChunk(new byte[10]);
+        mTask.finish(FullRestoreDownloader.FinishType.UNKNOWN_FINISH);
+
+        assertThat(mFolder.listFiles()).isEmpty();
+    }
+
+    /** Fake package wrapper which returns data from a byte array. */
+    private static class FakeFullRestoreDownloader extends FullRestoreDownloader {
+        private final ByteArrayInputStream mData;
+
+        FakeFullRestoreDownloader(byte[] data) {
+            // We override all methods of the superclass, so it does not require any collaborators.
+            super();
+            mData = new ByteArrayInputStream(data);
+        }
+
+        @Override
+        public int readNextChunk(byte[] buffer) throws IOException {
+            return mData.read(buffer);
+        }
+
+        @Override
+        public void finish(FinishType finishType) {
+            // Nothing to do.
+        }
+    }
+
+    /** Fake decrypts a byte array by subtracting 1 from each byte. */
+    private static byte[] fakeDecrypt(byte[] input) {
+        return Bytes.toArray(Bytes.asList(input).stream().map(b -> b + 1).collect(toList()));
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java
new file mode 100644
index 0000000..fa4fef5
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java
@@ -0,0 +1,356 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertThrows;
+
+import android.app.Application;
+import android.util.Pair;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.ProtoStore;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.TertiaryKeyManager;
+import com.android.server.backup.encryption.kv.KeyValueListingBuilder;
+import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.KeyValueListingProto;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+import com.android.server.backup.testing.CryptoTestUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.crypto.SecretKey;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class EncryptedKvBackupTaskTest {
+    private static final boolean INCREMENTAL = true;
+    private static final boolean NON_INCREMENTAL = false;
+
+    private static final String TEST_PACKAGE_1 = "com.example.app1";
+    private static final String TEST_KEY_1 = "key_1";
+    private static final String TEST_KEY_2 = "key_2";
+    private static final ChunkHash TEST_HASH_1 =
+            new ChunkHash(Arrays.copyOf(new byte[] {1}, ChunkHash.HASH_LENGTH_BYTES));
+    private static final ChunkHash TEST_HASH_2 =
+            new ChunkHash(Arrays.copyOf(new byte[] {2}, ChunkHash.HASH_LENGTH_BYTES));
+    private static final int TEST_LENGTH_1 = 200;
+    private static final int TEST_LENGTH_2 = 300;
+
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    @Captor private ArgumentCaptor<ChunksMetadataProto.ChunkListing> mChunkListingCaptor;
+
+    @Mock private TertiaryKeyManager mTertiaryKeyManager;
+    @Mock private RecoverableKeyStoreSecondaryKey mSecondaryKey;
+    @Mock private ProtoStore<KeyValueListingProto.KeyValueListing> mKeyValueListingStore;
+    @Mock private ProtoStore<ChunksMetadataProto.ChunkListing> mChunkListingStore;
+    @Mock private KvBackupEncrypter mKvBackupEncrypter;
+    @Mock private EncryptedBackupTask mEncryptedBackupTask;
+    @Mock private SecretKey mTertiaryKey;
+
+    private WrappedKeyProto.WrappedKey mWrappedTertiaryKey;
+    private KeyValueListingProto.KeyValueListing mNewKeyValueListing;
+    private ChunksMetadataProto.ChunkListing mNewChunkListing;
+    private EncryptedKvBackupTask mTask;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        Application application = ApplicationProvider.getApplicationContext();
+        mKeyValueListingStore = ProtoStore.createKeyValueListingStore(application);
+        mChunkListingStore = ProtoStore.createChunkListingStore(application);
+
+        mWrappedTertiaryKey = new WrappedKeyProto.WrappedKey();
+
+        when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(false);
+        when(mTertiaryKeyManager.getKey()).thenReturn(mTertiaryKey);
+        when(mTertiaryKeyManager.getWrappedKey()).thenReturn(mWrappedTertiaryKey);
+
+        mNewKeyValueListing =
+                createKeyValueListing(
+                        CryptoTestUtils.mapOf(
+                                new Pair<>(TEST_KEY_1, TEST_HASH_1),
+                                new Pair<>(TEST_KEY_2, TEST_HASH_2)));
+        mNewChunkListing =
+                createChunkListing(
+                        CryptoTestUtils.mapOf(
+                                new Pair<>(TEST_HASH_1, TEST_LENGTH_1),
+                                new Pair<>(TEST_HASH_2, TEST_LENGTH_2)));
+        when(mKvBackupEncrypter.getNewKeyValueListing()).thenReturn(mNewKeyValueListing);
+        when(mEncryptedBackupTask.performIncrementalBackup(
+                        eq(mTertiaryKey), eq(mWrappedTertiaryKey), any()))
+                .thenReturn(mNewChunkListing);
+        when(mEncryptedBackupTask.performNonIncrementalBackup(
+                        eq(mTertiaryKey), eq(mWrappedTertiaryKey), any()))
+                .thenReturn(mNewChunkListing);
+
+        mTask =
+                new EncryptedKvBackupTask(
+                        mTertiaryKeyManager,
+                        mKeyValueListingStore,
+                        mSecondaryKey,
+                        mChunkListingStore,
+                        mKvBackupEncrypter,
+                        mEncryptedBackupTask,
+                        TEST_PACKAGE_1);
+    }
+
+    @Test
+    public void testPerformBackup_rotationRequired_deletesListings() throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true);
+        // Throw an IOException so it aborts before saving the new listings.
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL));
+
+        assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+        assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+    }
+
+    @Test
+    public void testPerformBackup_rotationRequiredButIncremental_throws() throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true);
+
+        assertThrows(NonIncrementalBackupRequiredException.class,
+                () -> mTask.performBackup(INCREMENTAL));
+    }
+
+    @Test
+    public void testPerformBackup_rotationRequiredAndNonIncremental_performsNonIncrementalBackup()
+            throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        when(mTertiaryKeyManager.wasKeyRotated()).thenReturn(true);
+
+        mTask.performBackup(NON_INCREMENTAL);
+
+        verify(mEncryptedBackupTask)
+                .performNonIncrementalBackup(eq(mTertiaryKey), eq(mWrappedTertiaryKey), any());
+    }
+
+    @Test
+    public void testPerformBackup_existingStateButNonIncremental_deletesListings() throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        // Throw an IOException so it aborts before saving the new listings.
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL));
+
+        assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+        assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+    }
+
+    @Test
+    public void testPerformBackup_keyValueListingMissing_deletesChunkListingAndPerformsNonIncremental()
+            throws Exception {
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        // Throw an IOException so it aborts before saving the new listings.
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL));
+
+        verify(mEncryptedBackupTask).performNonIncrementalBackup(any(), any(), any());
+        assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+        assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+    }
+
+    @Test
+    public void testPerformBackup_chunkListingMissing_deletesKeyValueListingAndPerformsNonIncremental()
+            throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+
+        // Throw an IOException so it aborts before saving the new listings.
+        when(mEncryptedBackupTask.performNonIncrementalBackup(any(), any(), any()))
+                .thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> mTask.performBackup(NON_INCREMENTAL));
+
+        verify(mEncryptedBackupTask).performNonIncrementalBackup(any(), any(), any());
+        assertFalse(mKeyValueListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+        assertFalse(mChunkListingStore.loadProto(TEST_PACKAGE_1).isPresent());
+    }
+
+    @Test
+    public void testPerformBackup_existingStateAndIncremental_performsIncrementalBackup()
+            throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        ChunksMetadataProto.ChunkListing oldChunkListing =
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1)));
+        mChunkListingStore.saveProto(TEST_PACKAGE_1, oldChunkListing);
+
+        mTask.performBackup(INCREMENTAL);
+
+        verify(mEncryptedBackupTask)
+                .performIncrementalBackup(
+                        eq(mTertiaryKey), eq(mWrappedTertiaryKey), mChunkListingCaptor.capture());
+        assertChunkListingsEqual(mChunkListingCaptor.getValue(), oldChunkListing);
+    }
+
+    @Test
+    public void testPerformBackup_noExistingStateAndNonIncremental_performsNonIncrementalBackup()
+            throws Exception {
+        mTask.performBackup(NON_INCREMENTAL);
+
+        verify(mEncryptedBackupTask)
+                .performNonIncrementalBackup(eq(mTertiaryKey), eq(mWrappedTertiaryKey), eq(null));
+    }
+
+    @Test
+    public void testPerformBackup_incremental_savesNewListings() throws Exception {
+        mKeyValueListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createKeyValueListing(CryptoTestUtils.mapOf(new Pair<>(TEST_KEY_1, TEST_HASH_1))));
+        mChunkListingStore.saveProto(
+                TEST_PACKAGE_1,
+                createChunkListing(CryptoTestUtils.mapOf(new Pair<>(TEST_HASH_1, TEST_LENGTH_1))));
+
+        mTask.performBackup(INCREMENTAL);
+
+        KeyValueListingProto.KeyValueListing actualKeyValueListing =
+                mKeyValueListingStore.loadProto(TEST_PACKAGE_1).get();
+        ChunksMetadataProto.ChunkListing actualChunkListing =
+                mChunkListingStore.loadProto(TEST_PACKAGE_1).get();
+        assertKeyValueListingsEqual(actualKeyValueListing, mNewKeyValueListing);
+        assertChunkListingsEqual(actualChunkListing, mNewChunkListing);
+    }
+
+    @Test
+    public void testPerformBackup_nonIncremental_savesNewListings() throws Exception {
+        mTask.performBackup(NON_INCREMENTAL);
+
+        KeyValueListingProto.KeyValueListing actualKeyValueListing =
+                mKeyValueListingStore.loadProto(TEST_PACKAGE_1).get();
+        ChunksMetadataProto.ChunkListing actualChunkListing =
+                mChunkListingStore.loadProto(TEST_PACKAGE_1).get();
+        assertKeyValueListingsEqual(actualKeyValueListing, mNewKeyValueListing);
+        assertChunkListingsEqual(actualChunkListing, mNewChunkListing);
+    }
+
+    private static KeyValueListingProto.KeyValueListing createKeyValueListing(
+            Map<String, ChunkHash> pairs) {
+        return new KeyValueListingBuilder().addAll(pairs).build();
+    }
+
+    private static ChunksMetadataProto.ChunkListing createChunkListing(
+            Map<ChunkHash, Integer> chunks) {
+        ChunksMetadataProto.Chunk[] listingChunks = new ChunksMetadataProto.Chunk[chunks.size()];
+        int chunksAdded = 0;
+        for (Entry<ChunkHash, Integer> entry : chunks.entrySet()) {
+            listingChunks[chunksAdded] = CryptoTestUtils.newChunk(entry.getKey(), entry.getValue());
+            chunksAdded++;
+        }
+        return CryptoTestUtils.newChunkListingWithoutDocId(
+                /* fingerprintSalt */ new byte[0],
+                ChunksMetadataProto.AES_256_GCM,
+                ChunksMetadataProto.CHUNK_ORDERING_TYPE_UNSPECIFIED,
+                listingChunks);
+    }
+
+    private static void assertKeyValueListingsEqual(
+            KeyValueListingProto.KeyValueListing actual,
+            KeyValueListingProto.KeyValueListing expected) {
+        KeyValueListingProto.KeyValueEntry[] actualEntries = actual.entries;
+        KeyValueListingProto.KeyValueEntry[] expectedEntries = expected.entries;
+        assertThat(actualEntries.length).isEqualTo(expectedEntries.length);
+        for (int i = 0; i < actualEntries.length; i++) {
+            assertWithMessage("entry " + i)
+                    .that(actualEntries[i].key)
+                    .isEqualTo(expectedEntries[i].key);
+            assertWithMessage("entry " + i)
+                    .that(actualEntries[i].hash)
+                    .isEqualTo(expectedEntries[i].hash);
+        }
+    }
+
+    private static void assertChunkListingsEqual(
+            ChunksMetadataProto.ChunkListing actual, ChunksMetadataProto.ChunkListing expected) {
+        ChunksMetadataProto.Chunk[] actualChunks = actual.chunks;
+        ChunksMetadataProto.Chunk[] expectedChunks = expected.chunks;
+        assertThat(actualChunks.length).isEqualTo(expectedChunks.length);
+        for (int i = 0; i < actualChunks.length; i++) {
+            assertWithMessage("chunk " + i)
+                    .that(actualChunks[i].hash)
+                    .isEqualTo(expectedChunks[i].hash);
+            assertWithMessage("chunk " + i)
+                    .that(actualChunks[i].length)
+                    .isEqualTo(expectedChunks[i].length);
+        }
+        assertThat(actual.cipherType).isEqualTo(expected.cipherType);
+        assertThat(actual.documentId)
+                .isEqualTo(expected.documentId == null ? "" : expected.documentId);
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java
new file mode 100644
index 0000000..6666d95
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvRestoreTaskTest.java
@@ -0,0 +1,185 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.os.ParcelFileDescriptor;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.ChunkHasher;
+import com.android.server.backup.testing.CryptoTestUtils;
+import com.android.server.testing.shadows.DataEntity;
+import com.android.server.testing.shadows.ShadowBackupDataOutput;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@Config(shadows = {ShadowBackupDataOutput.class})
+@RunWith(RobolectricTestRunner.class)
+public class EncryptedKvRestoreTaskTest {
+    private static final String TEST_KEY_1 = "test_key_1";
+    private static final String TEST_KEY_2 = "test_key_2";
+    private static final String TEST_KEY_3 = "test_key_3";
+    private static final byte[] TEST_VALUE_1 = {1, 2, 3};
+    private static final byte[] TEST_VALUE_2 = {4, 5, 6};
+    private static final byte[] TEST_VALUE_3 = {20, 25, 30, 35};
+
+    @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+    private File temporaryDirectory;
+
+    @Mock private ParcelFileDescriptor mParcelFileDescriptor;
+    @Mock private ChunkHasher mChunkHasher;
+    @Mock private FullRestoreToFileTask mFullRestoreToFileTask;
+    @Mock private BackupFileDecryptorTask mBackupFileDecryptorTask;
+
+    private EncryptedKvRestoreTask task;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mChunkHasher.computeHash(any()))
+                .thenAnswer(invocation -> fakeHash(invocation.getArgument(0)));
+        doAnswer(invocation -> writeTestPairsToFile(invocation.getArgument(0)))
+                .when(mFullRestoreToFileTask)
+                .restoreToFile(any());
+        doAnswer(
+                        invocation ->
+                                readPairsFromFile(
+                                        invocation.getArgument(0), invocation.getArgument(1)))
+                .when(mBackupFileDecryptorTask)
+                .decryptFile(any(), any());
+
+        temporaryDirectory = temporaryFolder.newFolder();
+        task =
+                new EncryptedKvRestoreTask(
+                        temporaryDirectory,
+                        mChunkHasher,
+                        mFullRestoreToFileTask,
+                        mBackupFileDecryptorTask);
+    }
+
+    @Test
+    public void testGetRestoreData_writesPairsToOutputInOrder() throws Exception {
+        task.getRestoreData(mParcelFileDescriptor);
+
+        assertThat(ShadowBackupDataOutput.getEntities())
+                .containsExactly(
+                        new DataEntity(TEST_KEY_1, TEST_VALUE_1),
+                        new DataEntity(TEST_KEY_2, TEST_VALUE_2),
+                        new DataEntity(TEST_KEY_3, TEST_VALUE_3))
+                .inOrder();
+    }
+
+    @Test
+    public void testGetRestoreData_exceptionDuringDecryption_throws() throws Exception {
+        doThrow(IOException.class).when(mBackupFileDecryptorTask).decryptFile(any(), any());
+        assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor));
+    }
+
+    @Test
+    public void testGetRestoreData_exceptionDuringDownload_throws() throws Exception {
+        doThrow(IOException.class).when(mFullRestoreToFileTask).restoreToFile(any());
+        assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor));
+    }
+
+    @Test
+    public void testGetRestoreData_exceptionDuringDecryption_deletesTemporaryFiles() throws Exception {
+        doThrow(InvalidKeyException.class).when(mBackupFileDecryptorTask).decryptFile(any(), any());
+        assertThrows(InvalidKeyException.class, () -> task.getRestoreData(mParcelFileDescriptor));
+        assertThat(temporaryDirectory.listFiles()).isEmpty();
+    }
+
+    @Test
+    public void testGetRestoreData_exceptionDuringDownload_deletesTemporaryFiles() throws Exception {
+        doThrow(IOException.class).when(mFullRestoreToFileTask).restoreToFile(any());
+        assertThrows(IOException.class, () -> task.getRestoreData(mParcelFileDescriptor));
+        assertThat(temporaryDirectory.listFiles()).isEmpty();
+    }
+
+    private static Void writeTestPairsToFile(File file) throws IOException {
+        // Write the pairs out of order to check the task sorts them.
+        Set<byte[]> pairs =
+                new HashSet<>(
+                        Arrays.asList(
+                                createPair(TEST_KEY_1, TEST_VALUE_1),
+                                createPair(TEST_KEY_3, TEST_VALUE_3),
+                                createPair(TEST_KEY_2, TEST_VALUE_2)));
+
+        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) {
+            oos.writeObject(pairs);
+        }
+        return null;
+    }
+
+    private static Void readPairsFromFile(File file, DecryptedChunkOutput decryptedChunkOutput)
+            throws IOException, ClassNotFoundException, InvalidKeyException,
+                    NoSuchAlgorithmException {
+        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
+                DecryptedChunkOutput output = decryptedChunkOutput.open()) {
+            Set<byte[]> pairs = readPairs(ois);
+            for (byte[] pair : pairs) {
+                output.processChunk(pair, pair.length);
+            }
+        }
+
+        return null;
+    }
+
+    private static byte[] createPair(String key, byte[] value) {
+        return MessageNano.toByteArray(CryptoTestUtils.newPair(key, value));
+    }
+
+    @SuppressWarnings("unchecked") // deserialization.
+    private static Set<byte[]> readPairs(ObjectInputStream ois)
+            throws IOException, ClassNotFoundException {
+        return (Set<byte[]>) ois.readObject();
+    }
+
+    private static ChunkHash fakeHash(byte[] data) {
+        return new ChunkHash(Arrays.copyOf(data, ChunkHash.HASH_LENGTH_BYTES));
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java
new file mode 100644
index 0000000..de8b734
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/FullRestoreToFileTaskTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.encryption.FullRestoreDownloader;
+import com.android.server.backup.encryption.FullRestoreDownloader.FinishType;
+
+import com.google.common.io.Files;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.util.Random;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class FullRestoreToFileTaskTest {
+    private static final int TEST_RANDOM_SEED = 34;
+    private static final int TEST_MAX_CHUNK_SIZE_BYTES = 5;
+    private static final int TEST_DATA_LENGTH_BYTES = TEST_MAX_CHUNK_SIZE_BYTES * 20;
+
+    @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+    private byte[] mTestData;
+    private File mTargetFile;
+    private FakeFullRestoreDownloader mFakeFullRestoreDownloader;
+    @Mock private FullRestoreDownloader mMockFullRestoreDownloader;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mTargetFile = mTemporaryFolder.newFile();
+
+        mTestData = new byte[TEST_DATA_LENGTH_BYTES];
+        new Random(TEST_RANDOM_SEED).nextBytes(mTestData);
+        mFakeFullRestoreDownloader = new FakeFullRestoreDownloader(mTestData);
+    }
+
+    private FullRestoreToFileTask createTaskWithFakeDownloader() {
+        return new FullRestoreToFileTask(mFakeFullRestoreDownloader, TEST_MAX_CHUNK_SIZE_BYTES);
+    }
+
+    private FullRestoreToFileTask createTaskWithMockDownloader() {
+        return new FullRestoreToFileTask(mMockFullRestoreDownloader, TEST_MAX_CHUNK_SIZE_BYTES);
+    }
+
+    @Test
+    public void restoreToFile_readsDataAndWritesToFile() throws Exception {
+        FullRestoreToFileTask task = createTaskWithFakeDownloader();
+        task.restoreToFile(mTargetFile);
+        assertThat(Files.toByteArray(mTargetFile)).isEqualTo(mTestData);
+    }
+
+    @Test
+    public void restoreToFile_noErrors_closesDownloaderWithFinished() throws Exception {
+        FullRestoreToFileTask task = createTaskWithMockDownloader();
+        when(mMockFullRestoreDownloader.readNextChunk(any())).thenReturn(-1);
+
+        task.restoreToFile(mTargetFile);
+
+        verify(mMockFullRestoreDownloader).finish(FinishType.FINISHED);
+    }
+
+    @Test
+    public void restoreToFile_ioException_closesDownloaderWithTransferFailure() throws Exception {
+        FullRestoreToFileTask task = createTaskWithMockDownloader();
+        when(mMockFullRestoreDownloader.readNextChunk(any())).thenThrow(IOException.class);
+
+        assertThrows(IOException.class, () -> task.restoreToFile(mTargetFile));
+
+        verify(mMockFullRestoreDownloader).finish(FinishType.TRANSFER_FAILURE);
+    }
+
+    /** Fake package wrapper which returns data from a byte array. */
+    private static class FakeFullRestoreDownloader extends FullRestoreDownloader {
+
+        private final ByteArrayInputStream mData;
+
+        FakeFullRestoreDownloader(byte[] data) {
+            // We override all methods of the superclass, so it does not require any collaborators.
+            super();
+            this.mData = new ByteArrayInputStream(data);
+        }
+
+        @Override
+        public int readNextChunk(byte[] buffer) throws IOException {
+            return mData.read(buffer);
+        }
+
+        @Override
+        public void finish(FinishType finishType) {
+            // Do nothing.
+        }
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTaskTest.java
new file mode 100644
index 0000000..4a7ae03
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/InitializeRecoverableSecondaryKeyTaskTest.java
@@ -0,0 +1,165 @@
+/*
+ * 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.encryption.tasks;
+
+import static android.security.keystore.recovery.RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertThrows;
+
+import android.app.Application;
+import android.security.keystore.recovery.RecoveryController;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.testing.fakes.FakeCryptoBackupServer;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.util.Optional;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@Config(shadows = {ShadowRecoveryController.class})
+@RunWith(RobolectricTestRunner.class)
+public class InitializeRecoverableSecondaryKeyTaskTest {
+    @Mock private CryptoSettings mMockCryptoSettings;
+
+    private Application mApplication;
+    private InitializeRecoverableSecondaryKeyTask mTask;
+    private CryptoSettings mCryptoSettings;
+    private FakeCryptoBackupServer mFakeCryptoBackupServer;
+    private RecoverableKeyStoreSecondaryKeyManager mSecondaryKeyManager;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        ShadowRecoveryController.reset();
+
+        mApplication = ApplicationProvider.getApplicationContext();
+        mFakeCryptoBackupServer = new FakeCryptoBackupServer();
+        mCryptoSettings = CryptoSettings.getInstanceForTesting(mApplication);
+        mSecondaryKeyManager =
+                new RecoverableKeyStoreSecondaryKeyManager(
+                        RecoveryController.getInstance(mApplication), new SecureRandom());
+
+        mTask =
+                new InitializeRecoverableSecondaryKeyTask(
+                        mApplication, mCryptoSettings, mSecondaryKeyManager, mFakeCryptoBackupServer);
+    }
+
+    @Test
+    public void testRun_generatesNewKeyInRecoveryController() throws Exception {
+        RecoverableKeyStoreSecondaryKey key = mTask.run();
+
+        assertThat(RecoveryController.getInstance(mApplication).getAliases())
+                .contains(key.getAlias());
+    }
+
+    @Test
+    public void testRun_setsAliasOnServer() throws Exception {
+        RecoverableKeyStoreSecondaryKey key = mTask.run();
+
+        assertThat(mFakeCryptoBackupServer.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(key.getAlias());
+    }
+
+    @Test
+    public void testRun_setsAliasInSettings() throws Exception {
+        RecoverableKeyStoreSecondaryKey key = mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get()).isEqualTo(key.getAlias());
+    }
+
+    @Test
+    public void testRun_initializesSettings() throws Exception {
+        mTask.run();
+
+        assertThat(mCryptoSettings.getIsInitialized()).isTrue();
+    }
+
+    @Test
+    public void testRun_initializeSettingsFails_throws() throws Exception {
+        useMockCryptoSettings();
+        doThrow(IllegalArgumentException.class)
+                .when(mMockCryptoSettings)
+                .initializeWithKeyAlias(any());
+
+
+        assertThrows(IllegalArgumentException.class, () -> mTask.run());
+    }
+
+    @Test
+    public void testRun_doesNotGenerateANewKeyIfOneIsAvailable() throws Exception {
+        RecoverableKeyStoreSecondaryKey key1 = mTask.run();
+        RecoverableKeyStoreSecondaryKey key2 = mTask.run();
+
+        assertThat(key1.getAlias()).isEqualTo(key2.getAlias());
+        assertThat(key2.getSecretKey()).isEqualTo(key2.getSecretKey());
+    }
+
+    @Test
+    public void testRun_existingKeyButDestroyed_throws() throws Exception {
+        RecoverableKeyStoreSecondaryKey key = mTask.run();
+        ShadowRecoveryController.setRecoveryStatus(
+                key.getAlias(), RECOVERY_STATUS_PERMANENT_FAILURE);
+
+        assertThrows(InvalidKeyException.class, () -> mTask.run());
+    }
+
+    @Test
+    public void testRun_settingsInitializedButNotSecondaryKeyAlias_throws() {
+        useMockCryptoSettings();
+        when(mMockCryptoSettings.getIsInitialized()).thenReturn(true);
+        when(mMockCryptoSettings.getActiveSecondaryKeyAlias()).thenReturn(Optional.empty());
+
+        assertThrows(InvalidKeyException.class, () -> mTask.run());
+    }
+
+    @Test
+    public void testRun_keyAliasSetButNotInStore_throws() {
+        useMockCryptoSettings();
+        when(mMockCryptoSettings.getIsInitialized()).thenReturn(true);
+        when(mMockCryptoSettings.getActiveSecondaryKeyAlias())
+                .thenReturn(Optional.of("missingAlias"));
+
+        assertThrows(InvalidKeyException.class, () -> mTask.run());
+    }
+
+    private void useMockCryptoSettings() {
+        mTask =
+                new InitializeRecoverableSecondaryKeyTask(
+                        mApplication,
+                        mMockCryptoSettings,
+                        mSecondaryKeyManager,
+                        mFakeCryptoBackupServer);
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTaskTest.java
new file mode 100644
index 0000000..cda7317
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/RotateSecondaryKeyTaskTest.java
@@ -0,0 +1,363 @@
+/*
+ * 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.encryption.tasks;
+
+import static com.android.server.backup.testing.CryptoTestUtils.generateAesKey;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertFalse;
+
+import android.app.Application;
+import android.platform.test.annotations.Presubmit;
+import android.security.keystore.recovery.RecoveryController;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.backup.encryption.CryptoSettings;
+import com.android.server.backup.encryption.keys.KeyWrapUtils;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKey;
+import com.android.server.backup.encryption.keys.RecoverableKeyStoreSecondaryKeyManager;
+import com.android.server.backup.encryption.keys.TertiaryKeyStore;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+import com.android.server.testing.fakes.FakeCryptoBackupServer;
+import com.android.server.testing.shadows.ShadowRecoveryController;
+
+import java.security.SecureRandom;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.SecretKey;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+@Config(shadows = {ShadowRecoveryController.class, ShadowRecoveryController.class})
+public class RotateSecondaryKeyTaskTest {
+    private static final String APP_1 = "app1";
+    private static final String APP_2 = "app2";
+    private static final String APP_3 = "app3";
+
+    private static final String CURRENT_SECONDARY_KEY_ALIAS =
+            "recoverablekey.alias/d524796bd07de3c2225c63d434eff698";
+    private static final String NEXT_SECONDARY_KEY_ALIAS =
+            "recoverablekey.alias/6c6d198a7f12e662b6bc45f4849db170";
+
+    private Application mApplication;
+    private RotateSecondaryKeyTask mTask;
+    private RecoveryController mRecoveryController;
+    private FakeCryptoBackupServer mBackupServer;
+    private CryptoSettings mCryptoSettings;
+    private Map<String, SecretKey> mTertiaryKeysByPackageName;
+    private RecoverableKeyStoreSecondaryKeyManager mRecoverableSecondaryKeyManager;
+
+    @Before
+    public void setUp() throws Exception {
+        mApplication = ApplicationProvider.getApplicationContext();
+
+        mTertiaryKeysByPackageName = new HashMap<>();
+        mTertiaryKeysByPackageName.put(APP_1, generateAesKey());
+        mTertiaryKeysByPackageName.put(APP_2, generateAesKey());
+        mTertiaryKeysByPackageName.put(APP_3, generateAesKey());
+
+        mRecoveryController = RecoveryController.getInstance(mApplication);
+        mRecoverableSecondaryKeyManager =
+                new RecoverableKeyStoreSecondaryKeyManager(
+                        RecoveryController.getInstance(mApplication), new SecureRandom());
+        mBackupServer = new FakeCryptoBackupServer();
+        mCryptoSettings = CryptoSettings.getInstanceForTesting(mApplication);
+        addNextSecondaryKeyToRecoveryController();
+        mCryptoSettings.setNextSecondaryAlias(NEXT_SECONDARY_KEY_ALIAS);
+
+        mTask =
+                new RotateSecondaryKeyTask(
+                        mApplication,
+                        mRecoverableSecondaryKeyManager,
+                        mBackupServer,
+                        mCryptoSettings,
+                        mRecoveryController);
+
+        ShadowRecoveryController.reset();
+    }
+
+    @Test
+    public void run_failsIfThereIsNoActiveSecondaryKey() throws Exception {
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertFalse(mCryptoSettings.getActiveSecondaryKeyAlias().isPresent());
+    }
+
+    @Test
+    public void run_failsIfActiveSecondaryIsNotInRecoveryController() throws Exception {
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        // Have to add it first as otherwise CryptoSettings throws an exception when trying to set
+        // it
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(CURRENT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_doesNothingIfFlagIsDisabled() throws Exception {
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+        addWrappedTertiaries();
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(CURRENT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_setsActiveSecondary() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+        addWrappedTertiaries();
+
+        mTask.run();
+
+        assertThat(mBackupServer.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(NEXT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_rewrapsExistingTertiaryKeys() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+        addWrappedTertiaries();
+
+        mTask.run();
+
+        Map<String, WrappedKeyProto.WrappedKey> rewrappedKeys =
+                mBackupServer.getAllTertiaryKeys(NEXT_SECONDARY_KEY_ALIAS);
+        SecretKey secondaryKey = (SecretKey) mRecoveryController.getKey(NEXT_SECONDARY_KEY_ALIAS);
+        for (String packageName : mTertiaryKeysByPackageName.keySet()) {
+            WrappedKeyProto.WrappedKey rewrappedKey = rewrappedKeys.get(packageName);
+            assertThat(KeyWrapUtils.unwrap(secondaryKey, rewrappedKey))
+                    .isEqualTo(mTertiaryKeysByPackageName.get(packageName));
+        }
+    }
+
+    @Test
+    public void run_persistsRewrappedKeysToDisk() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+        addWrappedTertiaries();
+
+        mTask.run();
+
+        RecoverableKeyStoreSecondaryKey secondaryKey = getRecoverableKey(NEXT_SECONDARY_KEY_ALIAS);
+        Map<String, SecretKey> keys =
+                TertiaryKeyStore.newInstance(mApplication, secondaryKey).getAll();
+        for (String packageName : mTertiaryKeysByPackageName.keySet()) {
+            SecretKey tertiaryKey = mTertiaryKeysByPackageName.get(packageName);
+            SecretKey newlyWrappedKey = keys.get(packageName);
+            assertThat(tertiaryKey.getEncoded()).isEqualTo(newlyWrappedKey.getEncoded());
+        }
+    }
+
+    @Test
+    public void run_stillSetsActiveSecondaryIfNoTertiaries() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mBackupServer.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(NEXT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_setsActiveSecondaryKeyAliasInSettings() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(NEXT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_removesNextSecondaryKeyAliasInSettings() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertFalse(mCryptoSettings.getNextSecondaryKeyAlias().isPresent());
+    }
+
+    @Test
+    public void run_deletesOldKeyFromRecoverableKeyStoreLoader() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNCED);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mRecoveryController.getKey(CURRENT_SECONDARY_KEY_ALIAS)).isNull();
+    }
+
+    @Test
+    public void run_doesNotRotateIfNoNextAlias() throws Exception {
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+        mCryptoSettings.removeNextSecondaryKeyAlias();
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(CURRENT_SECONDARY_KEY_ALIAS);
+        assertFalse(mCryptoSettings.getNextSecondaryKeyAlias().isPresent());
+    }
+
+    @Test
+    public void run_doesNotRotateIfKeyIsNotSyncedYet() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(CURRENT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_doesNotClearNextKeyIfSyncIsJustPending() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getNextSecondaryKeyAlias().get())
+                .isEqualTo(NEXT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_doesNotRotateIfPermanentFailure() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertThat(mCryptoSettings.getActiveSecondaryKeyAlias().get())
+                .isEqualTo(CURRENT_SECONDARY_KEY_ALIAS);
+    }
+
+    @Test
+    public void run_removesNextKeyIfPermanentFailure() throws Exception {
+        addNextSecondaryKeyToRecoveryController();
+        setNextKeyRecoveryStatus(RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE);
+        addCurrentSecondaryKeyToRecoveryController();
+        mCryptoSettings.setActiveSecondaryKeyAlias(CURRENT_SECONDARY_KEY_ALIAS);
+        mBackupServer.setActiveSecondaryKeyAlias(
+                CURRENT_SECONDARY_KEY_ALIAS, Collections.emptyMap());
+
+        mTask.run();
+
+        assertFalse(mCryptoSettings.getNextSecondaryKeyAlias().isPresent());
+    }
+
+    private void setNextKeyRecoveryStatus(int status) throws Exception {
+        mRecoveryController.setRecoveryStatus(NEXT_SECONDARY_KEY_ALIAS, status);
+    }
+
+    private void addCurrentSecondaryKeyToRecoveryController() throws Exception {
+        mRecoveryController.generateKey(CURRENT_SECONDARY_KEY_ALIAS);
+    }
+
+    private void addNextSecondaryKeyToRecoveryController() throws Exception {
+        mRecoveryController.generateKey(NEXT_SECONDARY_KEY_ALIAS);
+    }
+
+    private void addWrappedTertiaries() throws Exception {
+        TertiaryKeyStore tertiaryKeyStore =
+                TertiaryKeyStore.newInstance(
+                        mApplication, getRecoverableKey(CURRENT_SECONDARY_KEY_ALIAS));
+
+        for (String packageName : mTertiaryKeysByPackageName.keySet()) {
+            tertiaryKeyStore.save(packageName, mTertiaryKeysByPackageName.get(packageName));
+        }
+    }
+
+    private RecoverableKeyStoreSecondaryKey getRecoverableKey(String alias) throws Exception {
+        return mRecoverableSecondaryKeyManager.get(alias).get();
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java
index b9055ce..b0c02ba 100644
--- a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/CryptoTestUtils.java
@@ -16,11 +16,17 @@
 
 package com.android.server.backup.testing;
 
+import android.util.Pair;
+
 import com.android.server.backup.encryption.chunk.ChunkHash;
 import com.android.server.backup.encryption.protos.nano.ChunksMetadataProto;
+import com.android.server.backup.encryption.protos.nano.KeyValuePairProto;
 
+import java.nio.charset.Charset;
 import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Random;
 
 import javax.crypto.KeyGenerator;
@@ -76,7 +82,10 @@
             int orderingType,
             ChunksMetadataProto.Chunk... chunks) {
         ChunksMetadataProto.ChunkListing chunkListing = new ChunksMetadataProto.ChunkListing();
-        chunkListing.fingerprintMixerSalt = Arrays.copyOf(fingerprintSalt, fingerprintSalt.length);
+        chunkListing.fingerprintMixerSalt =
+                fingerprintSalt == null
+                        ? null
+                        : Arrays.copyOf(fingerprintSalt, fingerprintSalt.length);
         chunkListing.cipherType = cipherType;
         chunkListing.chunkOrderingType = orderingType;
         chunkListing.chunks = chunks;
@@ -86,11 +95,33 @@
     public static ChunksMetadataProto.ChunkOrdering newChunkOrdering(
             int[] starts, byte[] checksum) {
         ChunksMetadataProto.ChunkOrdering chunkOrdering = new ChunksMetadataProto.ChunkOrdering();
-        chunkOrdering.starts = Arrays.copyOf(starts, starts.length);
-        chunkOrdering.checksum = Arrays.copyOf(checksum, checksum.length);
+        chunkOrdering.starts = starts == null ? null : Arrays.copyOf(starts, starts.length);
+        chunkOrdering.checksum =
+                checksum == null ? checksum : Arrays.copyOf(checksum, checksum.length);
         return chunkOrdering;
     }
 
+    public static ChunksMetadataProto.ChunksMetadata newChunksMetadata(
+            int cipherType, int checksumType, int chunkOrderingType, byte[] chunkOrdering) {
+        ChunksMetadataProto.ChunksMetadata metadata = new ChunksMetadataProto.ChunksMetadata();
+        metadata.cipherType = cipherType;
+        metadata.checksumType = checksumType;
+        metadata.chunkOrdering = Arrays.copyOf(chunkOrdering, chunkOrdering.length);
+        metadata.chunkOrderingType = chunkOrderingType;
+        return metadata;
+    }
+
+    public static KeyValuePairProto.KeyValuePair newPair(String key, String value) {
+        return newPair(key, value.getBytes(Charset.forName("UTF-8")));
+    }
+
+    public static KeyValuePairProto.KeyValuePair newPair(String key, byte[] value) {
+        KeyValuePairProto.KeyValuePair newPair = new KeyValuePairProto.KeyValuePair();
+        newPair.key = key;
+        newPair.value = value;
+        return newPair;
+    }
+
     public static ChunksMetadataProto.ChunkListing clone(
             ChunksMetadataProto.ChunkListing original) {
         ChunksMetadataProto.Chunk[] clonedChunks;
@@ -114,4 +145,33 @@
     public static ChunksMetadataProto.Chunk clone(ChunksMetadataProto.Chunk original) {
         return newChunk(original.hash, original.length);
     }
+
+    public static ChunksMetadataProto.ChunksMetadata clone(
+            ChunksMetadataProto.ChunksMetadata original) {
+        ChunksMetadataProto.ChunksMetadata cloneMetadata = new ChunksMetadataProto.ChunksMetadata();
+        cloneMetadata.chunkOrderingType = original.chunkOrderingType;
+        cloneMetadata.chunkOrdering =
+                original.chunkOrdering == null
+                        ? null
+                        : Arrays.copyOf(original.chunkOrdering, original.chunkOrdering.length);
+        cloneMetadata.checksumType = original.checksumType;
+        cloneMetadata.cipherType = original.cipherType;
+        return cloneMetadata;
+    }
+
+    public static ChunksMetadataProto.ChunkOrdering clone(
+            ChunksMetadataProto.ChunkOrdering original) {
+        ChunksMetadataProto.ChunkOrdering clone = new ChunksMetadataProto.ChunkOrdering();
+        clone.starts = Arrays.copyOf(original.starts, original.starts.length);
+        clone.checksum = Arrays.copyOf(original.checksum, original.checksum.length);
+        return clone;
+    }
+
+    public static <K, V> Map<K, V> mapOf(Pair<K, V>... pairs) {
+        Map<K, V> map = new HashMap<>();
+        for (Pair<K, V> pair : pairs) {
+            map.put(pair.first, pair.second);
+        }
+        return map;
+    }
 }
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java
new file mode 100644
index 0000000..e5d73ba
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/TestFileUtils.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.google.common.io.ByteStreams;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/** Utility methods for use in tests */
+public class TestFileUtils {
+    /** Read the contents of a file into a byte array */
+    public static byte[] toByteArray(File file) throws IOException {
+        try (FileInputStream fis = new FileInputStream(file)) {
+            return ByteStreams.toByteArray(fis);
+        }
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServer.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServer.java
new file mode 100644
index 0000000..3329060
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServer.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.testing.fakes;
+
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.backup.encryption.client.CryptoBackupServer;
+import com.android.server.backup.encryption.client.UnexpectedActiveSecondaryOnServerException;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+/** Fake {@link CryptoBackupServer}, for tests. Stores tertiary keys in memory. */
+public class FakeCryptoBackupServer implements CryptoBackupServer {
+    @GuardedBy("this")
+    @Nullable
+    private String mActiveSecondaryKeyAlias;
+
+    // Secondary key alias -> (package name -> tertiary key)
+    @GuardedBy("this")
+    private Map<String, Map<String, WrappedKeyProto.WrappedKey>> mWrappedKeyStore = new HashMap<>();
+
+    @Override
+    public String uploadIncrementalBackup(
+            String packageName,
+            String oldDocId,
+            byte[] diffScript,
+            WrappedKeyProto.WrappedKey tertiaryKey) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String uploadNonIncrementalBackup(
+            String packageName, byte[] data, WrappedKeyProto.WrappedKey tertiaryKey) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public synchronized void setActiveSecondaryKeyAlias(
+            String keyAlias, Map<String, WrappedKeyProto.WrappedKey> tertiaryKeys) {
+        mActiveSecondaryKeyAlias = keyAlias;
+
+        mWrappedKeyStore.putIfAbsent(keyAlias, new HashMap<>());
+        Map<String, WrappedKeyProto.WrappedKey> keyStore = mWrappedKeyStore.get(keyAlias);
+
+        for (String packageName : tertiaryKeys.keySet()) {
+            keyStore.put(packageName, tertiaryKeys.get(packageName));
+        }
+    }
+
+    public synchronized Optional<String> getActiveSecondaryKeyAlias() {
+        return Optional.ofNullable(mActiveSecondaryKeyAlias);
+    }
+
+    public synchronized Map<String, WrappedKeyProto.WrappedKey> getAllTertiaryKeys(
+            String secondaryKeyAlias) throws UnexpectedActiveSecondaryOnServerException {
+        if (!secondaryKeyAlias.equals(mActiveSecondaryKeyAlias)) {
+            throw new UnexpectedActiveSecondaryOnServerException(
+                    String.format(
+                            Locale.US,
+                            "Requested tertiary keys wrapped with %s but %s was active secondary.",
+                            secondaryKeyAlias,
+                            mActiveSecondaryKeyAlias));
+        }
+
+        if (!mWrappedKeyStore.containsKey(secondaryKeyAlias)) {
+            return Collections.emptyMap();
+        }
+        return new HashMap<>(mWrappedKeyStore.get(secondaryKeyAlias));
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServerTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServerTest.java
new file mode 100644
index 0000000..4cd8333b
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/fakes/FakeCryptoBackupServerTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.testing.fakes;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertThrows;
+
+import android.util.Pair;
+
+import com.android.server.backup.encryption.client.UnexpectedActiveSecondaryOnServerException;
+import com.android.server.backup.encryption.protos.nano.WrappedKeyProto;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class FakeCryptoBackupServerTest {
+    private static final String PACKAGE_NAME_1 = "package1";
+    private static final String PACKAGE_NAME_2 = "package2";
+    private static final String PACKAGE_NAME_3 = "package3";
+    private static final WrappedKeyProto.WrappedKey PACKAGE_KEY_1 = createWrappedKey("key1");
+    private static final WrappedKeyProto.WrappedKey PACKAGE_KEY_2 = createWrappedKey("key2");
+    private static final WrappedKeyProto.WrappedKey PACKAGE_KEY_3 = createWrappedKey("key3");
+
+    private FakeCryptoBackupServer mServer;
+
+    @Before
+    public void setUp() {
+        mServer = new FakeCryptoBackupServer();
+    }
+
+    @Test
+    public void getActiveSecondaryKeyAlias_isInitiallyAbsent() throws Exception {
+        assertFalse(mServer.getActiveSecondaryKeyAlias().isPresent());
+    }
+
+    @Test
+    public void setActiveSecondaryKeyAlias_setsTheKeyAlias() throws Exception {
+        String keyAlias = "test";
+        mServer.setActiveSecondaryKeyAlias(keyAlias, Collections.emptyMap());
+        assertThat(mServer.getActiveSecondaryKeyAlias().get()).isEqualTo(keyAlias);
+    }
+
+    @Test
+    public void getAllTertiaryKeys_returnsWrappedKeys() throws Exception {
+        Map<String, WrappedKeyProto.WrappedKey> entries =
+                createKeyMap(
+                        new Pair<>(PACKAGE_NAME_1, PACKAGE_KEY_1),
+                        new Pair<>(PACKAGE_NAME_2, PACKAGE_KEY_2));
+        String secondaryKeyAlias = "doge";
+        mServer.setActiveSecondaryKeyAlias(secondaryKeyAlias, entries);
+
+        assertThat(mServer.getAllTertiaryKeys(secondaryKeyAlias)).containsExactlyEntriesIn(entries);
+    }
+
+    @Test
+    public void addTertiaryKeys_updatesExistingSet() throws Exception {
+        String keyId = "karlin";
+        WrappedKeyProto.WrappedKey replacementKey = createWrappedKey("some replacement bytes");
+
+        mServer.setActiveSecondaryKeyAlias(
+                keyId,
+                createKeyMap(
+                        new Pair<>(PACKAGE_NAME_1, PACKAGE_KEY_1),
+                        new Pair<>(PACKAGE_NAME_2, PACKAGE_KEY_2)));
+
+        mServer.setActiveSecondaryKeyAlias(
+                keyId,
+                createKeyMap(
+                        new Pair<>(PACKAGE_NAME_1, replacementKey),
+                        new Pair<>(PACKAGE_NAME_3, PACKAGE_KEY_3)));
+
+        assertThat(mServer.getAllTertiaryKeys(keyId))
+                .containsExactlyEntriesIn(
+                        createKeyMap(
+                                new Pair<>(PACKAGE_NAME_1, replacementKey),
+                                new Pair<>(PACKAGE_NAME_2, PACKAGE_KEY_2),
+                                new Pair<>(PACKAGE_NAME_3, PACKAGE_KEY_3)));
+    }
+
+    @Test
+    public void getAllTertiaryKeys_throwsForUnknownSecondaryKeyAlias() throws Exception {
+        assertThrows(
+                UnexpectedActiveSecondaryOnServerException.class,
+                () -> mServer.getAllTertiaryKeys("unknown"));
+    }
+
+    @Test
+    public void uploadIncrementalBackup_throwsUnsupportedOperationException() {
+        assertThrows(
+                UnsupportedOperationException.class,
+                () ->
+                        mServer.uploadIncrementalBackup(
+                                PACKAGE_NAME_1,
+                                "docid",
+                                new byte[0],
+                                new WrappedKeyProto.WrappedKey()));
+    }
+
+    @Test
+    public void uploadNonIncrementalBackup_throwsUnsupportedOperationException() {
+        assertThrows(
+                UnsupportedOperationException.class,
+                () ->
+                        mServer.uploadNonIncrementalBackup(
+                                PACKAGE_NAME_1, new byte[0], new WrappedKeyProto.WrappedKey()));
+    }
+
+    private static WrappedKeyProto.WrappedKey createWrappedKey(String data) {
+        WrappedKeyProto.WrappedKey wrappedKey = new WrappedKeyProto.WrappedKey();
+        wrappedKey.key = data.getBytes(Charset.forName("UTF-8"));
+        return wrappedKey;
+    }
+
+    private Map<String, WrappedKeyProto.WrappedKey> createKeyMap(
+            Pair<String, WrappedKeyProto.WrappedKey>... pairs) {
+        Map<String, WrappedKeyProto.WrappedKey> map = new HashMap<>();
+        for (Pair<String, WrappedKeyProto.WrappedKey> pair : pairs) {
+            map.put(pair.first, pair.second);
+        }
+        return map;
+    }
+}
diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
new file mode 100644
index 0000000..2302e55
--- /dev/null
+++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
@@ -0,0 +1,66 @@
+/*
+ * 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.testing.shadows;
+
+import android.app.backup.BackupDataOutput;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Assert;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/** Shadow for BackupDataOutput. */
+@Implements(BackupDataOutput.class)
+public class ShadowBackupDataOutput {
+    private static final List<DataEntity> ENTRIES = new ArrayList<>();
+
+    private String mCurrentKey;
+    private int mDataSize;
+
+    public static void reset() {
+        ENTRIES.clear();
+    }
+
+    public static Set<DataEntity> getEntities() {
+        return new LinkedHashSet<>(ENTRIES);
+    }
+
+    public void __constructor__(FileDescriptor fd) {}
+
+    public void __constructor__(FileDescriptor fd, long quota) {}
+
+    public void __constructor__(FileDescriptor fd, long quota, int transportFlags) {}
+
+    @Implementation
+    public int writeEntityHeader(String key, int size) {
+        mCurrentKey = key;
+        mDataSize = size;
+        return 0;
+    }
+
+    @Implementation
+    public int writeEntityData(byte[] data, int size) {
+        Assert.assertEquals("ShadowBackupDataOutput expects size = mDataSize", size, mDataSize);
+        ENTRIES.add(new DataEntity(mCurrentKey, data, mDataSize));
+        return 0;
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
index afd722b..447e579 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.BatteryController;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -34,8 +35,9 @@
     @Inject
     public CarNotificationInterruptionStateProvider(Context context,
             NotificationFilter filter,
-            StatusBarStateController stateController) {
-        super(context, filter, stateController);
+            StatusBarStateController stateController,
+            BatteryController batteryController) {
+        super(context, filter, stateController, batteryController);
     }
 
     @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 58f80a4..d79849c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarBatteryController.java
@@ -257,6 +257,11 @@
         return false;
     }
 
+    @Override
+    public boolean isAodPowerSave() {
+        return false;
+    }
+
     private void notifyBatteryLevelChanged() {
         for (int i = 0, size = mChangeCallbacks.size(); i < size; i++) {
             mChangeCallbacks.get(i)
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8f47470..1f923af 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1004,9 +1004,9 @@
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging -->
     <string name="power_charging"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="state">%2$s</xliff:g></string>
     <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery charging -->
-    <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until fully charged</string>
+    <string name="power_remaining_charging_duration_only"><xliff:g id="time">%1$s</xliff:g> left until charged</string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
-    <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until fully charged</string>
+    <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> until charged</string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 6a90671..19c6664 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -865,6 +865,10 @@
         void handleRebuildList() {
             AppFilter filter;
             Comparator<AppEntry> comparator;
+
+            if (!mResumed) {
+                return;
+            }
             synchronized (mRebuildSync) {
                 if (!mRebuildRequested) {
                     return;
@@ -1069,8 +1073,8 @@
                 }
             }
             if (rebuildingSessions != null) {
-                for (int i = 0; i < rebuildingSessions.size(); i++) {
-                    rebuildingSessions.get(i).handleRebuildList();
+                for (Session session : rebuildingSessions) {
+                    session.handleRebuildList();
                 }
             }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
index 5c9a06f9..4e052f1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/ThreadUtils.java
@@ -26,7 +26,7 @@
 
     private static volatile Thread sMainThread;
     private static volatile Handler sMainThreadHandler;
-    private static volatile ExecutorService sSingleThreadExecutor;
+    private static volatile ExecutorService sThreadExecutor;
 
     /**
      * Returns true if the current thread is the UI thread.
@@ -64,10 +64,11 @@
      * @Return A future of the task that can be monitored for updates or cancelled.
      */
     public static Future postOnBackgroundThread(Runnable runnable) {
-        if (sSingleThreadExecutor == null) {
-            sSingleThreadExecutor = Executors.newSingleThreadExecutor();
+        if (sThreadExecutor == null) {
+            sThreadExecutor = Executors.newFixedThreadPool(
+                    Runtime.getRuntime().availableProcessors());
         }
-        return sSingleThreadExecutor.submit(runnable);
+        return sThreadExecutor.submit(runnable);
     }
 
     /**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index f8697a1..95a4f69b 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -269,7 +269,7 @@
     }
 
     @Test
-    public void testDefaultSessionLoadsAll() {
+    public void testDefaultSession_isResumed_LoadsAll() {
         mSession.onResume();
 
         addApp(HOME_PACKAGE_NAME, 1);
@@ -296,6 +296,19 @@
     }
 
     @Test
+    public void testDefaultSession_isPaused_NotLoadsAll() {
+        mSession.onResume();
+
+        addApp(HOME_PACKAGE_NAME, 1);
+        addApp(LAUNCHABLE_PACKAGE_NAME, 2);
+        mSession.mResumed = false;
+        mSession.rebuild(ApplicationsState.FILTER_EVERYTHING, ApplicationsState.SIZE_COMPARATOR);
+        processAllMessages();
+
+        verify(mCallbacks, never()).onRebuildComplete(mAppEntriesCaptor.capture());
+    }
+
+    @Test
     public void testCustomSessionLoadsIconsOnly() {
         mSession.setSessionFlags(ApplicationsState.FLAG_SESSION_REQUEST_ICONS);
         mSession.onResume();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
index 26db124..5114b00 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/ThreadUtilsTest.java
@@ -50,7 +50,7 @@
     }
 
     @Test
-    public void testPostOnMainThread_shouldRunOnMainTread() {
+    public void testPostOnMainThread_shouldRunOnMainThread() {
         TestRunnable cr = new TestRunnable();
         ShadowLooper.pauseMainLooper();
         ThreadUtils.postOnMainThread(cr);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 046ffc3..2ce4e97 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -76,7 +76,7 @@
                 ConfigSettingsProto.RUNTIME_NATIVE_SETTINGS);
         namespaceToFieldMap.put(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
                 ConfigSettingsProto.RUNTIME_NATIVE_BOOT_SETTINGS);
-        namespaceToFieldMap.put(DeviceConfig.NAMESPACE_STORAGE,
+        namespaceToFieldMap.put(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
                 ConfigSettingsProto.STORAGE_SETTINGS);
         namespaceToFieldMap.put(DeviceConfig.NAMESPACE_SYSTEMUI,
                 ConfigSettingsProto.SYSTEMUI_SETTINGS);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 3a7de18..86625fa 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -719,7 +719,8 @@
                  Settings.Secure.BIOMETRIC_DEBUG_ENABLED,
                  Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED,
                  Settings.Secure.FACE_UNLOCK_DIVERSITY_REQUIRED,
-                 Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED);
+                 Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED,
+                 Settings.Secure.FACE_UNLOCK_RE_ENROLL);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e767bcc..e11c063 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -29,6 +29,7 @@
     <uses-permission android:name="android.permission.CALL_PHONE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
+    <uses-permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION" />
     <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
@@ -240,7 +241,7 @@
 
         <activity
             android:name=".BugreportWarningActivity"
-            android:theme="@android:style/Theme.DeviceDefault.Dialog.Alert"
+            android:theme="@*android:style/Theme.DeviceDefault.Dialog.Alert.DayNight"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true"
             android:exported="false" />
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 0fe7084..485240a 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -62,7 +62,7 @@
 
     <!-- When the lock screen is showing, the phone is plugged in and the battery is fully
          charged, say that it is charged. -->
-    <string name="keyguard_charged">Fully charged</string>
+    <string name="keyguard_charged">Charged</string>
 
     <!-- When the lock screen is showing and the phone plugged in, and the battery is not fully charged, say that it's wirelessly charging. [CHAR LIMIT=50]  -->
     <string name="keyguard_plugged_in_wireless"><xliff:g id="percentage" example="20%">%s</xliff:g> • Charging wirelessly</string>
diff --git a/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png b/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
new file mode 100644
index 0000000..135dabb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/tv_card_gradient_protection.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/circle_red.xml b/packages/SystemUI/res/drawable/circle_red.xml
new file mode 100644
index 0000000..fd3c125
--- /dev/null
+++ b/packages/SystemUI/res/drawable/circle_red.xml
@@ -0,0 +1,21 @@
+<?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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="oval">
+    <solid android:color="@color/red"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml b/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml
new file mode 100644
index 0000000..1bbb8c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_bg_item_app_info.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <corners android:radius="24dp"/>
+    <solid android:color="@color/tv_audio_recording_bar_chip_background"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_gradient_protection.xml b/packages/SystemUI/res/drawable/tv_gradient_protection.xml
new file mode 100644
index 0000000..ee5cbc7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_gradient_protection.xml
@@ -0,0 +1,22 @@
+<?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.
+  -->
+
+<!-- gradient protection for cards -->
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/tv_card_gradient_protection"
+        android:tileMode="repeat"
+/>
diff --git a/packages/SystemUI/res/drawable/tv_ic_mic_white.xml b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
new file mode 100644
index 0000000..1bea8a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_ic_mic_white.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:viewportWidth="44"
+        android:viewportHeight="44"
+        android:width="44dp"
+        android:height="44dp">
+    <path
+        android:pathData="M22 25.6666667C25.0433333 25.6666667 27.4816667 23.21 27.4816667 20.1666667L27.5 9.16666667C27.5 6.12333333 25.0433333 3.66666667 22 3.66666667C18.9566667 3.66666667 16.5 6.12333333 16.5 9.16666667L16.5 20.1666667C16.5 23.21 18.9566667 25.6666667 22 25.6666667ZM31.7166667 20.1666667C31.7166667 25.6666667 27.06 29.5166667 22 29.5166667C16.94 29.5166667 12.2833333 25.6666667 12.2833333 20.1666667L9.16666667 20.1666667C9.16666667 26.4183333 14.1533333 31.5883333 20.1666667 32.4866667L20.1666667 38.5L23.8333333 38.5L23.8333333 32.4866667C29.8466667 31.6066667 34.8333333 26.4366667 34.8333333 20.1666667L31.7166667 20.1666667Z"
+        android:fillColor="@android:color/white" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_carrier_group.xml b/packages/SystemUI/res/layout/qs_carrier_group.xml
index 56efb49..f2b0606 100644
--- a/packages/SystemUI/res/layout/qs_carrier_group.xml
+++ b/packages/SystemUI/res/layout/qs_carrier_group.xml
@@ -29,6 +29,9 @@
         android:id="@+id/no_carrier_text"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:minWidth="48dp"
+        android:minHeight="48dp"
+        android:gravity="center_vertical"
         android:textAppearance="@style/TextAppearance.QS.Status"
         android:textDirection="locale"
         android:marqueeRepeatLimit="marquee_forever"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
index 4849dfb..7d6ff3b1 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_plugin_frame.xml
@@ -20,10 +20,10 @@
     android:id="@+id/plugin_frame"
     android:theme="@style/qs_theme"
     android:layout_width="@dimen/qs_panel_width"
-    android:layout_height="96dp"
+    android:layout_height="105dp"
     android:layout_gravity="center_horizontal"
-    android:layout_marginTop="@*android:dimen/quick_qs_total_height"
+    android:layout_marginTop="@dimen/notification_side_paddings"
     android:layout_marginLeft="@dimen/notification_side_paddings"
     android:layout_marginRight="@dimen/notification_side_paddings"
     android:visibility="gone"
-    android:background="@drawable/qs_background_primary"/>
\ No newline at end of file
+    android:background="@drawable/qs_background_primary"/>
diff --git a/packages/SystemUI/res/layout/tv_item_app_info.xml b/packages/SystemUI/res/layout/tv_item_app_info.xml
new file mode 100644
index 0000000..b40589e
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_item_app_info.xml
@@ -0,0 +1,41 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:layout_width="wrap_content"
+              android:layout_height="48dp"
+              android:layout_marginLeft="8dp"
+              android:paddingHorizontal="12dp"
+              android:gravity="center_vertical"
+              android:background="@drawable/tv_bg_item_app_info">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="24dp"
+        android:layout_height="24dp"
+        android:layout_marginRight="8dp"/>
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/tv_audio_recording_bar_text"
+        android:fontFamily="sans-serif"
+        android:textSize="14sp"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml b/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
new file mode 100644
index 0000000..b9dffbb
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_status_bar_audio_recording.xml
@@ -0,0 +1,63 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:layout_gravity="bottom"
+              android:orientation="vertical">
+
+    <!-- Gradient Protector -->
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="102.5dp"
+        android:background="@drawable/tv_gradient_protection"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="72dp"
+        android:background="@color/tv_audio_recording_bar_background"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+
+        <ImageView
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_marginLeft="42dp"
+            android:layout_marginVertical="12dp"
+            android:padding="8dp"
+            android:background="@drawable/circle_red"
+            android:scaleType="centerInside"
+            android:src="@drawable/tv_ic_mic_white"/>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="24dp"
+            android:text="Audio recording by"
+            android:textColor="@color/tv_audio_recording_bar_text"
+            android:fontFamily="sans-serif"
+            android:textSize="14sp"/>
+
+        <LinearLayout
+            android:id="@+id/container"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 9197bb5..1fe6141 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -33,4 +33,8 @@
         <item>com.google.android.tungsten.setupwraith/.settings.usage.UsageDiagnosticsSettingActivity</item>
         <item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
     </string-array>
+
+    <string-array name="audio_recording_disclosure_exempt_apps" translatable="false">
+      <item>com.google.android.katniss</item>
+    </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 6e56d4a..db225428 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -21,4 +21,14 @@
     <color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
     <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
     <color name="recents_tv_text_shadow_color">#7F000000</color>
+
+
+    <!-- Text color used in audio recording bar: G50 -->
+    <color name="tv_audio_recording_bar_text">#FFF8F9FA</color>
+    <!-- Background color for a chip in audio recording bar: G800 -->
+    <color name="tv_audio_recording_bar_chip_background">#FF3C4043</color>
+    <!-- Audio recording bar background color: G900 -->
+    <color name="tv_audio_recording_bar_background">#FF202124</color>
+
+    <color name="red">#FFCC0000</color>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0be84ee..c554780 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -863,6 +863,8 @@
     <string name="quick_settings_notifications_label">Notifications</string>
     <!-- QuickSettings: Flashlight [CHAR LIMIT=NONE] -->
     <string name="quick_settings_flashlight_label">Flashlight</string>
+    <!-- QuickSettings: Flashlight, used when it's not available due to camera in use [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_flashlight_camera_in_use">Camera in use</string>
     <!-- QuickSettings: Cellular detail panel title [CHAR LIMIT=NONE] -->
     <string name="quick_settings_cellular_detail_title">Mobile data</string>
     <!-- QuickSettings: Cellular detail panel, data usage title [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index e1b723e..949941b 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -167,7 +167,7 @@
         mSeparator = separator;
         mWakefulnessLifecycle = Dependency.get(WakefulnessLifecycle.class);
         mSimSlotsNumber = ((TelephonyManager) context.getSystemService(
-                Context.TELEPHONY_SERVICE)).getPhoneCount();
+                Context.TELEPHONY_SERVICE)).getMaxPhoneCount();
         mSimErrorState = new boolean[mSimSlotsNumber];
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 720074b..a6b3be2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -219,7 +219,7 @@
 
     private final Context mContext;
     private final boolean mIsPrimaryUser;
-    HashMap<Integer, SimData> mSimDatas = new HashMap<Integer, SimData>();
+    HashMap<Integer, SimData> mSimDatas = new HashMap<>();
     HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
 
     private int mRingMode;
@@ -2512,8 +2512,7 @@
     @MainThread
     public void reportSimUnlocked(int subId) {
         if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")");
-        int slotId = SubscriptionManager.getSlotIndex(subId);
-        handleSimStateChange(subId, slotId, State.READY);
+        handleSimStateChange(subId, getSlotId(subId), State.READY);
     }
 
     /**
@@ -2586,6 +2585,13 @@
         }
     }
 
+    private int getSlotId(int subId) {
+        if (!mSimDatas.containsKey(subId)) {
+            refreshSimState(subId, SubscriptionManager.getSlotIndex(subId));
+        }
+        return mSimDatas.get(subId).slotId;
+    }
+
     private final TaskStackChangeListener
             mTaskStackListener = new TaskStackChangeListener() {
         @Override
@@ -2710,7 +2716,7 @@
         for (int i = 0; i < list.size(); i++) {
             final SubscriptionInfo info = list.get(i);
             final int id = info.getSubscriptionId();
-            int slotId = SubscriptionManager.getSlotIndex(id);
+            int slotId = getSlotId(id);
             if (state == getSimState(id) && bestSlotId > slotId) {
                 resultId = id;
                 bestSlotId = slotId;
@@ -2752,7 +2758,7 @@
 
     private void checkIsHandlerThread() {
         if (!mHandler.getLooper().isCurrentThread()) {
-            Log.wtf(TAG, "must call on mHandler's thread "
+            Log.wtfStack(TAG, "must call on mHandler's thread "
                     + mHandler.getLooper().getThread() + ", not " + Thread.currentThread());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
index 0e079e3..5c561e5 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceLifetimeExtender.java
@@ -83,7 +83,9 @@
                 }
             }
         };
-        mHandler.postDelayed(r, MIN_FGS_TIME_MS);
+        long delayAmt = MIN_FGS_TIME_MS
+                - (System.currentTimeMillis() - entry.notification.getPostTime());
+        mHandler.postDelayed(r, delayAmt);
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java
index 0fa80ac..ba2dec0 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIBinder.java
@@ -18,6 +18,9 @@
 
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.power.PowerUI;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsModule;
+import com.android.systemui.util.leak.GarbageMonitor;
 
 import dagger.Binds;
 import dagger.Module;
@@ -27,7 +30,7 @@
 /**
  * SystemUI objects that are injectable should go here.
  */
-@Module
+@Module(includes = {RecentsModule.class})
 public abstract class SystemUIBinder {
     /** Inject into KeyguardViewMediator. */
     @Binds
@@ -40,4 +43,16 @@
     @IntoMap
     @ClassKey(PowerUI.class)
     public abstract SystemUI bindPowerUI(PowerUI sysui);
+
+    /** Inject into StatusBar. */
+    @Binds
+    @IntoMap
+    @ClassKey(Recents.class)
+    public abstract SystemUI bindRecents(Recents sysui);
+
+    /** Inject into GarbageMonitor.Service. */
+    @Binds
+    @IntoMap
+    @ClassKey(GarbageMonitor.Service.class)
+    public abstract SystemUI bindGarbageMonitorService(GarbageMonitor.Service service);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
index c70b2fc..bcbe672 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
@@ -23,7 +23,6 @@
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.InjectionInflationController;
-import com.android.systemui.util.leak.GarbageMonitor;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -43,7 +42,7 @@
 public interface SystemUIRootComponent {
 
     /**
-     * Creates a GarbageMonitor.
+     * Creates a ContextComponentHelper.
      */
     @Singleton
     ContextComponentHelper getContextComponentHelper();
@@ -72,12 +71,6 @@
     InjectionInflationController.ViewCreator createViewCreator();
 
     /**
-     * Creates a GarbageMonitor.
-     */
-    @Singleton
-    GarbageMonitor createGarbageMonitor();
-
-    /**
      * Whether notification long press is allowed.
      */
     @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
index bf81e1d..9958124 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/DefaultUiController.java
@@ -152,7 +152,8 @@
                     .setSubtype(Dependency.get(AssistManager.class).toLoggingSubType(type)));
         }
         // Logs assistant invocation cancelled.
-        if (!mInvocationAnimator.isRunning() && invocationWasInProgress && progress == 0f) {
+        if ((mInvocationAnimator == null || !mInvocationAnimator.isRunning())
+                && invocationWasInProgress && progress == 0f) {
             if (VERBOSE) {
                 Log.v(TAG, "Invocation cancelled: type=" + type);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
index 9ae02c5..baa3a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/EdgeLight.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.assist.ui;
 
+import android.util.Log;
+
 import androidx.annotation.ColorInt;
 
 /**
@@ -29,9 +31,12 @@
  * counter-clockwise.
  */
 public final class EdgeLight {
+
+    private static final String TAG = "EdgeLight";
+
     @ColorInt
     private int mColor;
-    private float mOffset;
+    private float mStart;
     private float mLength;
 
     /** Copies a list of EdgeLights. */
@@ -45,13 +50,13 @@
 
     public EdgeLight(@ColorInt int color, float offset, float length) {
         mColor = color;
-        mOffset = offset;
+        mStart = offset;
         mLength = length;
     }
 
     public EdgeLight(EdgeLight sourceLight) {
         mColor = sourceLight.getColor();
-        mOffset = sourceLight.getOffset();
+        mStart = sourceLight.getStart();
         mLength = sourceLight.getLength();
     }
 
@@ -77,23 +82,41 @@
     }
 
     /**
-     * Returns the current offset, in units of the total device perimeter and measured from the
-     * bottom-left corner (see class description).
+     * Sets the endpoints of the edge light, both measured from the bottom-left corner (see class
+     * description). This is a convenience method to avoid separate setStart and setLength calls.
      */
-    public float getOffset() {
-        return mOffset;
+    public void setEndpoints(float start, float end) {
+        if (start > end) {
+            Log.e(TAG, String.format("Endpoint must be >= start (add 1 if necessary). Got [%f, %f]",
+                    start, end));
+            return;
+        }
+        mStart = start;
+        mLength = end - start;
+    }
+
+    /**
+     * Returns the current starting position, in units of the total device perimeter and measured
+     * from the bottom-left corner (see class description).
+     */
+    public float getStart() {
+        return mStart;
     }
 
     /**
      * Sets the current offset, in units of the total device perimeter and measured from the
      * bottom-left corner (see class description).
      */
-    public void setOffset(float offset) {
-        mOffset = offset;
+    public void setStart(float start) {
+        mStart = start;
+    }
+
+    public float getEnd() {
+        return mStart + mLength;
     }
 
     /** Returns the center, measured from the bottom-left corner (see class description). */
     public float getCenter() {
-        return mOffset + (mLength / 2.f);
+        return mStart + (mLength / 2.f);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index bb3bd78..570b911 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -140,10 +140,10 @@
             float rightStart = mGuide.getRegionWidth(PerimeterPathGuide.Region.BOTTOM)
                     + (cornerLengthNormalized - arcOffsetNormalized) * (1 - progress);
 
-            setLight(0, leftStart, lightLength);
-            setLight(1, leftStart + lightLength, lightLength);
-            setLight(2, rightStart - (lightLength * 2), lightLength);
-            setLight(3, rightStart - lightLength, lightLength);
+            setLight(0, leftStart, leftStart + lightLength);
+            setLight(1, leftStart + lightLength, leftStart + lightLength * 2);
+            setLight(2, rightStart - (lightLength * 2), rightStart - lightLength);
+            setLight(3, rightStart - lightLength, rightStart);
             setVisibility(View.VISIBLE);
         }
         invalidate();
@@ -155,7 +155,7 @@
     public void hide() {
         setVisibility(GONE);
         for (EdgeLight light : mAssistInvocationLights) {
-            light.setLength(0);
+            light.setEndpoints(0, 0);
         }
         attemptUnregisterNavBarListener();
     }
@@ -235,12 +235,11 @@
         }
     }
 
-    protected void setLight(int index, float offset, float length) {
+    protected void setLight(int index, float start, float end) {
         if (index < 0 || index >= 4) {
             Log.w(TAG, "invalid invocation light index: " + index);
         }
-        mAssistInvocationLights.get(index).setOffset(offset);
-        mAssistInvocationLights.get(index).setLength(length);
+        mAssistInvocationLights.get(index).setEndpoints(start, end);
     }
 
     /**
@@ -268,9 +267,11 @@
     }
 
     private void renderLight(EdgeLight light, Canvas canvas) {
-        mGuide.strokeSegment(mPath, light.getOffset(), light.getOffset() + light.getLength());
-        mPaint.setColor(light.getColor());
-        canvas.drawPath(mPath, mPaint);
+        if (light.getLength() > 0) {
+            mGuide.strokeSegment(mPath, light.getStart(), light.getStart() + light.getLength());
+            mPaint.setColor(light.getColor());
+            canvas.drawPath(mPath, mPaint);
+        }
     }
 
     private void attemptRegisterNavBarListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 1d7e9ea..419fd62 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -82,7 +82,7 @@
 
     private void requestPulse(State dozeState) {
         if (!mDozeHost.isPulsingBlocked() && dozeState.canPulse()) {
-            mMachine.requestPulse(DozeLog.PULSE_REASON_DOCKING);
+            mMachine.requestPulse(DozeEvent.PULSE_REASON_DOCKING);
         }
         mPulsePending = false;
     }
@@ -91,7 +91,7 @@
         if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING
                 || dozeState == State.DOZE_PULSING_BRIGHT) {
             final int pulseReason = mMachine.getPulseReason();
-            if (pulseReason == DozeLog.PULSE_REASON_DOCKING) {
+            if (pulseReason == DozeEvent.PULSE_REASON_DOCKING) {
                 mDozeHost.stopPulsing();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java
new file mode 100644
index 0000000..ea1def0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeEvent.java
@@ -0,0 +1,154 @@
+/*
+ * 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.doze;
+
+import android.annotation.IntDef;
+
+import com.android.systemui.log.RichEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An event related to dozing. {@link DozeLog} stores and prints these events for debugging
+ * and triaging purposes.
+ */
+public class DozeEvent extends RichEvent {
+    public static final int TOTAL_EVENT_TYPES = 19;
+
+    public DozeEvent(int logLevel, int type, String reason) {
+        super(logLevel, type, reason);
+    }
+
+    /**
+     * Event labels for each doze event
+     * Index corresponds to the integer associated with each {@link EventType}
+     */
+    @Override
+    public String[] getEventLabels() {
+        final String[] events = new String[]{
+                "PickupWakeup",
+                "PulseStart",
+                "PulseFinish",
+                "NotificationPulse",
+                "Dozing",
+                "Fling",
+                "EmergencyCall",
+                "KeyguardBouncerChanged",
+                "ScreenOn",
+                "ScreenOff",
+                "MissedTick",
+                "TimeTickScheduled",
+                "KeyguardVisibilityChanged",
+                "DozeStateChanged",
+                "WakeDisplay",
+                "ProximityResult",
+                "PulseDropped",
+                "PulseDisabledByProx",
+                "SensorTriggered"
+        };
+
+        if (events.length != TOTAL_EVENT_TYPES) {
+            throw new IllegalStateException("DozeEvent events.length should match TOTAL_EVENT_TYPES"
+                    + " events.length=" + events.length
+                    + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES);
+        }
+        return events;
+    }
+
+    /**
+     * Converts the reason (integer) to a user-readable string
+     */
+    public static String reasonToString(@Reason int pulseReason) {
+        switch (pulseReason) {
+            case PULSE_REASON_INTENT: return "intent";
+            case PULSE_REASON_NOTIFICATION: return "notification";
+            case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
+            case REASON_SENSOR_PICKUP: return "pickup";
+            case REASON_SENSOR_DOUBLE_TAP: return "doubletap";
+            case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
+            case PULSE_REASON_DOCKING: return "docking";
+            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
+            case REASON_SENSOR_WAKE_UP: return "wakeup";
+            case REASON_SENSOR_TAP: return "tap";
+            default: throw new IllegalArgumentException("invalid reason: " + pulseReason);
+        }
+    }
+
+    /**
+     * Builds a DozeEvent.
+     */
+    public static class DozeEventBuilder extends RichEvent.Builder<DozeEventBuilder> {
+        @Override
+        public DozeEventBuilder getBuilder() {
+            return this;
+        }
+
+        @Override
+        public RichEvent build() {
+            return new DozeEvent(mLogLevel, mType, mReason);
+        }
+    }
+
+    @IntDef({PICKUP_WAKEUP, PULSE_START, PULSE_FINISH, NOTIFICATION_PULSE, DOZING, FLING,
+            EMERGENCY_CALL, KEYGUARD_BOUNCER_CHANGED, SCREEN_ON, SCREEN_OFF, MISSED_TICK,
+            TIME_TICK_SCHEDULED, KEYGUARD_VISIBILITY_CHANGE, DOZE_STATE_CHANGED, WAKE_DISPLAY,
+            PROXIMITY_RESULT, PULSE_DROPPED, PULSE_DISABLED_BY_PROX, SENSOR_TRIGGERED})
+    /**
+     * Types of DozeEvents
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EventType {}
+    public static final int PICKUP_WAKEUP = 0;
+    public static final int PULSE_START = 1;
+    public static final int PULSE_FINISH = 2;
+    public static final int NOTIFICATION_PULSE = 3;
+    public static final int DOZING = 4;
+    public static final int FLING = 5;
+    public static final int EMERGENCY_CALL = 6;
+    public static final int KEYGUARD_BOUNCER_CHANGED = 7;
+    public static final int SCREEN_ON = 8;
+    public static final int SCREEN_OFF = 9;
+    public static final int MISSED_TICK = 10;
+    public static final int TIME_TICK_SCHEDULED = 11;
+    public static final int KEYGUARD_VISIBILITY_CHANGE = 12;
+    public static final int DOZE_STATE_CHANGED = 13;
+    public static final int WAKE_DISPLAY = 14;
+    public static final int PROXIMITY_RESULT = 15;
+    public static final int PULSE_DROPPED = 16;
+    public static final int PULSE_DISABLED_BY_PROX = 17;
+    public static final int SENSOR_TRIGGERED = 18;
+
+    public static final int TOTAL_REASONS = 10;
+    @IntDef({PULSE_REASON_NONE, PULSE_REASON_INTENT, PULSE_REASON_NOTIFICATION,
+            PULSE_REASON_SENSOR_SIGMOTION, REASON_SENSOR_PICKUP, REASON_SENSOR_DOUBLE_TAP,
+            PULSE_REASON_SENSOR_LONG_PRESS, PULSE_REASON_DOCKING, REASON_SENSOR_WAKE_UP,
+            PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, REASON_SENSOR_TAP})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Reason {}
+    public static final int PULSE_REASON_NONE = -1;
+    public static final int PULSE_REASON_INTENT = 0;
+    public static final int PULSE_REASON_NOTIFICATION = 1;
+    public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
+    public static final int REASON_SENSOR_PICKUP = 3;
+    public static final int REASON_SENSOR_DOUBLE_TAP = 4;
+    public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
+    public static final int PULSE_REASON_DOCKING = 6;
+    public static final int REASON_SENSOR_WAKE_UP = 7;
+    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
+    public static final int REASON_SENSOR_TAP = 9;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 4d3dc70..ca4ec6d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -33,6 +33,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.phone.BiometricUnlockController;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 import com.android.systemui.util.sensors.ProximitySensor;
 import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -44,7 +45,8 @@
     }
 
     /** Creates a DozeMachine with its parts for {@code dozeService}. */
-    public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager) {
+    public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager,
+            DozeLog dozeLog) {
         Context context = dozeService;
         AsyncSensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
         AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
@@ -65,13 +67,14 @@
                 params);
 
         DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
-                wakefulnessLifecycle);
+                wakefulnessLifecycle, Dependency.get(BatteryController.class), dozeLog);
         machine.setParts(new DozeMachine.Part[]{
                 new DozePauser(handler, machine, alarmManager, params.getPolicy()),
                 new DozeFalsingManagerAdapter(falsingManager),
                 createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
-                        handler, wakeLock, machine, dockManager),
-                createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
+                        handler, wakeLock, machine, dockManager, dozeLog),
+                createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params,
+                        dozeLog),
                 new DozeScreenState(wrappedService, handler, params, wakeLock),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
@@ -95,18 +98,19 @@
     private DozeTriggers createDozeTriggers(Context context, AsyncSensorManager sensorManager,
             DozeHost host, AlarmManager alarmManager, AmbientDisplayConfiguration config,
             DozeParameters params, Handler handler, WakeLock wakeLock, DozeMachine machine,
-            DockManager dockManager) {
+            DockManager dockManager, DozeLog dozeLog) {
         boolean allowPulseTriggers = true;
         return new DozeTriggers(context, machine, host, alarmManager, config, params,
                 sensorManager, handler, wakeLock, allowPulseTriggers, dockManager,
-                new ProximitySensor(context, sensorManager));
+                new ProximitySensor(context, sensorManager), dozeLog);
+
     }
 
     private DozeMachine.Part createDozeUi(Context context, DozeHost host, WakeLock wakeLock,
             DozeMachine machine, Handler handler, AlarmManager alarmManager,
-            DozeParameters params) {
+            DozeParameters params, DozeLog dozeLog) {
         return new DozeUi(context, alarmManager, machine, wakeLock, host, handler, params,
-                Dependency.get(KeyguardUpdateMonitor.class));
+                Dependency.get(KeyguardUpdateMonitor.class), dozeLog);
     }
 
     public static DozeHost getHost(DozeService service) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 8fe9f92..2e4466d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -16,282 +16,284 @@
 
 package com.android.systemui.doze;
 
-import android.content.Context;
-import android.os.Build;
-import android.util.Log;
 import android.util.TimeUtils;
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.Dependency;
+import com.android.systemui.DumpController;
+import com.android.systemui.log.SysuiLog;
 
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
 import java.util.Date;
 
-public class DozeLog {
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Logs doze events for debugging and triaging purposes. Logs are dumped in bugreports or on demand:
+ *      adb shell dumpsys activity service com.android.systemui/.SystemUIService \
+ *      dependency DumpController DozeLog
+ */
+@Singleton
+public class DozeLog extends SysuiLog {
     private static final String TAG = "DozeLog";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean ENABLED = true;
-    private static final int SIZE = Build.IS_DEBUGGABLE ? 400 : 50;
-    static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
 
-    public static final int REASONS = 10;
+    private boolean mPulsing;
+    private long mSince;
+    private SummaryStats mPickupPulseNearVibrationStats;
+    private SummaryStats mPickupPulseNotNearVibrationStats;
+    private SummaryStats mNotificationPulseStats;
+    private SummaryStats mScreenOnPulsingStats;
+    private SummaryStats mScreenOnNotPulsingStats;
+    private SummaryStats mEmergencyCallStats;
+    private SummaryStats[][] mProxStats; // [reason][near/far]
 
-    public static final int PULSE_REASON_NONE = -1;
-    public static final int PULSE_REASON_INTENT = 0;
-    public static final int PULSE_REASON_NOTIFICATION = 1;
-    public static final int PULSE_REASON_SENSOR_SIGMOTION = 2;
-    public static final int REASON_SENSOR_PICKUP = 3;
-    public static final int REASON_SENSOR_DOUBLE_TAP = 4;
-    public static final int PULSE_REASON_SENSOR_LONG_PRESS = 5;
-    public static final int PULSE_REASON_DOCKING = 6;
-    public static final int REASON_SENSOR_WAKE_UP = 7;
-    public static final int PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN = 8;
-    public static final int REASON_SENSOR_TAP = 9;
+    @Inject
+    public DozeLog(KeyguardUpdateMonitor keyguardUpdateMonitor, DumpController dumpController) {
+        super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS);
+        mSince = System.currentTimeMillis();
+        mPickupPulseNearVibrationStats = new SummaryStats();
+        mPickupPulseNotNearVibrationStats = new SummaryStats();
+        mNotificationPulseStats = new SummaryStats();
+        mScreenOnPulsingStats = new SummaryStats();
+        mScreenOnNotPulsingStats = new SummaryStats();
+        mEmergencyCallStats = new SummaryStats();
+        mProxStats = new SummaryStats[DozeEvent.TOTAL_REASONS][2];
+        for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
+            mProxStats[i][0] = new SummaryStats();
+            mProxStats[i][1] = new SummaryStats();
+        }
 
-    private static boolean sRegisterKeyguardCallback = true;
-
-    private static long[] sTimes;
-    private static String[] sMessages;
-    private static int sPosition;
-    private static int sCount;
-    private static boolean sPulsing;
-
-    private static long sSince;
-    private static SummaryStats sPickupPulseNearVibrationStats;
-    private static SummaryStats sPickupPulseNotNearVibrationStats;
-    private static SummaryStats sNotificationPulseStats;
-    private static SummaryStats sScreenOnPulsingStats;
-    private static SummaryStats sScreenOnNotPulsingStats;
-    private static SummaryStats sEmergencyCallStats;
-    private static SummaryStats[][] sProxStats; // [reason][near/far]
-
-    public static void tracePickupWakeUp(Context context, boolean withinVibrationThreshold) {
-        if (!ENABLED) return;
-        init(context);
-        log("pickupWakeUp withinVibrationThreshold=" + withinVibrationThreshold);
-        (withinVibrationThreshold ? sPickupPulseNearVibrationStats
-                : sPickupPulseNotNearVibrationStats).append();
-    }
-
-    public static void tracePulseStart(int reason) {
-        if (!ENABLED) return;
-        sPulsing = true;
-        log("pulseStart reason=" + reasonToString(reason));
-    }
-
-    public static void tracePulseFinish() {
-        if (!ENABLED) return;
-        sPulsing = false;
-        log("pulseFinish");
-    }
-
-    public static void traceNotificationPulse(Context context) {
-        if (!ENABLED) return;
-        init(context);
-        log("notificationPulse");
-        sNotificationPulseStats.append();
-    }
-
-    private static void init(Context context) {
-        synchronized (DozeLog.class) {
-            if (sMessages == null) {
-                sTimes = new long[SIZE];
-                sMessages = new String[SIZE];
-                sSince = System.currentTimeMillis();
-                sPickupPulseNearVibrationStats = new SummaryStats();
-                sPickupPulseNotNearVibrationStats = new SummaryStats();
-                sNotificationPulseStats = new SummaryStats();
-                sScreenOnPulsingStats = new SummaryStats();
-                sScreenOnNotPulsingStats = new SummaryStats();
-                sEmergencyCallStats = new SummaryStats();
-                sProxStats = new SummaryStats[REASONS][2];
-                for (int i = 0; i < REASONS; i++) {
-                    sProxStats[i][0] = new SummaryStats();
-                    sProxStats[i][1] = new SummaryStats();
-                }
-                log("init");
-                if (sRegisterKeyguardCallback) {
-                    Dependency.get(KeyguardUpdateMonitor.class).registerCallback(sKeyguardCallback);
-                }
-            }
+        if (keyguardUpdateMonitor != null) {
+            keyguardUpdateMonitor.registerCallback(mKeyguardCallback);
         }
     }
 
-    public static void traceDozing(Context context, boolean dozing) {
-        if (!ENABLED) return;
-        sPulsing = false;
-        init(context);
-        log("dozing " + dozing);
+    /**
+     * Appends pickup wakeup event to the logs
+     */
+    public void tracePickupWakeUp(boolean withinVibrationThreshold) {
+        if (log(DozeEvent.PICKUP_WAKEUP,
+                "withinVibrationThreshold=" + withinVibrationThreshold)) {
+            (withinVibrationThreshold ? mPickupPulseNearVibrationStats
+                    : mPickupPulseNotNearVibrationStats).append();
+        }
     }
 
-    public static void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
+    /**
+     * Appends pulse started event to the logs.
+     * @param reason why the pulse started
+     */
+    public void tracePulseStart(@DozeEvent.Reason int reason) {
+        if (log(DozeEvent.PULSE_START, DozeEvent.reasonToString(reason))) {
+            mPulsing = true;
+        }
+    }
+
+    /**
+     * Appends pulse finished event to the logs
+     */
+    public void tracePulseFinish() {
+        if (log(DozeEvent.PULSE_FINISH)) {
+            mPulsing = false;
+        }
+    }
+
+    /**
+     * Appends pulse event to the logs
+     */
+    public void traceNotificationPulse() {
+        if (log(DozeEvent.NOTIFICATION_PULSE)) {
+            mNotificationPulseStats.append();
+        }
+    }
+
+    /**
+     * Appends dozing event to the logs
+     * @param dozing true if dozing, else false
+     */
+    public void traceDozing(boolean dozing) {
+        if (log(DozeEvent.DOZING, "dozing=" + dozing)) {
+            mPulsing = false;
+        }
+    }
+
+    /**
+     * Appends fling event to the logs
+     */
+    public void traceFling(boolean expand, boolean aboveThreshold, boolean thresholdNeeded,
             boolean screenOnFromTouch) {
-        if (!ENABLED) return;
-        log("fling expand=" + expand + " aboveThreshold=" + aboveThreshold + " thresholdNeeded="
-                + thresholdNeeded + " screenOnFromTouch=" + screenOnFromTouch);
+        log(DozeEvent.FLING, "expand=" + expand
+                + " aboveThreshold=" + aboveThreshold
+                + " thresholdNeeded=" + thresholdNeeded
+                + " screenOnFromTouch=" + screenOnFromTouch);
     }
 
-    public static void traceEmergencyCall() {
-        if (!ENABLED) return;
-        log("emergencyCall");
-        sEmergencyCallStats.append();
-    }
-
-    public static void traceKeyguardBouncerChanged(boolean showing) {
-        if (!ENABLED) return;
-        log("bouncer " + showing);
-    }
-
-    public static void traceScreenOn() {
-        if (!ENABLED) return;
-        log("screenOn pulsing=" + sPulsing);
-        (sPulsing ? sScreenOnPulsingStats : sScreenOnNotPulsingStats).append();
-        sPulsing = false;
-    }
-
-    public static void traceScreenOff(int why) {
-        if (!ENABLED) return;
-        log("screenOff why=" + why);
-    }
-
-    public static void traceMissedTick(String delay) {
-        if (!ENABLED) return;
-        log("missedTick by=" + delay);
-    }
-
-    public static void traceTimeTickScheduled(long when, long triggerAt) {
-        if (!ENABLED) return;
-        log("timeTickScheduled at=" + FORMAT.format(new Date(when)) + " triggerAt="
-                + FORMAT.format(new Date(triggerAt)));
-    }
-
-    public static void traceKeyguard(boolean showing) {
-        if (!ENABLED) return;
-        log("keyguard " + showing);
-        if (!showing) {
-            sPulsing = false;
+    /**
+     * Appends emergency call event to the logs
+     */
+    public void traceEmergencyCall() {
+        if (log(DozeEvent.EMERGENCY_CALL)) {
+            mEmergencyCallStats.append();
         }
     }
 
-    public static void traceState(DozeMachine.State state) {
-        if (!ENABLED) return;
-        log("state " + state);
+    /**
+     * Appends keyguard bouncer changed event to the logs
+     * @param showing true if the keyguard bouncer is showing, else false
+     */
+    public void traceKeyguardBouncerChanged(boolean showing) {
+        log(DozeEvent.KEYGUARD_BOUNCER_CHANGED, "showing=" + showing);
+    }
+
+    /**
+     * Appends screen-on event to the logs
+     */
+    public void traceScreenOn() {
+        if (log(DozeEvent.SCREEN_ON, "pulsing=" + mPulsing)) {
+            (mPulsing ? mScreenOnPulsingStats : mScreenOnNotPulsingStats).append();
+            mPulsing = false;
+        }
+    }
+
+    /**
+     * Appends screen-off event to the logs
+     * @param why reason the screen is off
+     */
+    public void traceScreenOff(int why) {
+        log(DozeEvent.SCREEN_OFF, "why=" + why);
+    }
+
+    /**
+     * Appends missed tick event to the logs
+     * @param delay of the missed tick
+     */
+    public void traceMissedTick(String delay) {
+        log(DozeEvent.MISSED_TICK, "delay=" + delay);
+    }
+
+    /**
+     * Appends time tick scheduled event to the logs
+     * @param when time tick scheduled at
+     * @param triggerAt time tick trigger at
+     */
+    public void traceTimeTickScheduled(long when, long triggerAt) {
+        log(DozeEvent.TIME_TICK_SCHEDULED,
+                "scheduledAt=" + DATE_FORMAT.format(new Date(when))
+                + " triggerAt=" + DATE_FORMAT.format(new Date(triggerAt)));
+    }
+
+    /**
+     * Appends keyguard visibility change event to the logs
+     * @param showing whether the keyguard is now showing
+     */
+    public void traceKeyguard(boolean showing) {
+        if (log(DozeEvent.KEYGUARD_VISIBILITY_CHANGE, "showing=" + showing)
+                && !showing) {
+            mPulsing = false;
+        }
+    }
+
+    /**
+     * Appends doze state changed event to the logs
+     * @param state new DozeMachine state
+     */
+    public void traceState(DozeMachine.State state) {
+        log(DozeEvent.DOZE_STATE_CHANGED, state.name());
     }
 
     /**
      * Appends wake-display event to the logs.
      * @param wake if we're waking up or sleeping.
      */
-    public static void traceWakeDisplay(boolean wake) {
-        if (!ENABLED) return;
-        log("wakeDisplay " + wake);
+    public void traceWakeDisplay(boolean wake) {
+        log(DozeEvent.WAKE_DISPLAY, "wake=" + wake);
     }
 
-    public static void traceProximityResult(Context context, boolean near, long millis,
-            int reason) {
-        if (!ENABLED) return;
-        init(context);
-        log("proximityResult reason=" + reasonToString(reason) + " near=" + near
-                + " millis=" + millis);
-        sProxStats[reason][near ? 0 : 1].append();
-    }
-
-    public static String reasonToString(int pulseReason) {
-        switch (pulseReason) {
-            case PULSE_REASON_INTENT: return "intent";
-            case PULSE_REASON_NOTIFICATION: return "notification";
-            case PULSE_REASON_SENSOR_SIGMOTION: return "sigmotion";
-            case REASON_SENSOR_PICKUP: return "pickup";
-            case REASON_SENSOR_DOUBLE_TAP: return "doubletap";
-            case PULSE_REASON_SENSOR_LONG_PRESS: return "longpress";
-            case PULSE_REASON_DOCKING: return "docking";
-            case PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN: return "wakelockscreen";
-            case REASON_SENSOR_WAKE_UP: return "wakeup";
-            case REASON_SENSOR_TAP: return "tap";
-            default: throw new IllegalArgumentException("bad reason: " + pulseReason);
+    /**
+     * Appends proximity result event to the logs
+     * @param near true if near, else false
+     * @param millis
+     * @param reason why proximity result was triggered
+     */
+    public void traceProximityResult(boolean near, long millis, @DozeEvent.Reason int reason) {
+        if (log(DozeEvent.PROXIMITY_RESULT,
+                " reason=" + DozeEvent.reasonToString(reason)
+                + " near=" + near
+                + " millis=" + millis)) {
+            mProxStats[reason][near ? 0 : 1].append();
         }
     }
 
-    public static void dump(PrintWriter pw) {
+    /**
+     * Prints doze log timeline and consolidated stats
+     * @param pw
+     */
+    public void dump(PrintWriter pw) {
         synchronized (DozeLog.class) {
-            if (sMessages == null) return;
-            pw.println("  Doze log:");
-            final int start = (sPosition - sCount + SIZE) % SIZE;
-            for (int i = 0; i < sCount; i++) {
-                final int j = (start + i) % SIZE;
-                pw.print("    ");
-                pw.print(FORMAT.format(new Date(sTimes[j])));
-                pw.print(' ');
-                pw.println(sMessages[j]);
-            }
+            super.dump(null, pw, null); // prints timeline
+
             pw.print("  Doze summary stats (for ");
-            TimeUtils.formatDuration(System.currentTimeMillis() - sSince, pw);
+            TimeUtils.formatDuration(System.currentTimeMillis() - mSince, pw);
             pw.println("):");
-            sPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
-            sPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
-            sNotificationPulseStats.dump(pw, "Notification pulse");
-            sScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
-            sScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
-            sEmergencyCallStats.dump(pw, "Emergency call");
-            for (int i = 0; i < REASONS; i++) {
-                final String reason = reasonToString(i);
-                sProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
-                sProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
+            mPickupPulseNearVibrationStats.dump(pw, "Pickup pulse (near vibration)");
+            mPickupPulseNotNearVibrationStats.dump(pw, "Pickup pulse (not near vibration)");
+            mNotificationPulseStats.dump(pw, "Notification pulse");
+            mScreenOnPulsingStats.dump(pw, "Screen on (pulsing)");
+            mScreenOnNotPulsingStats.dump(pw, "Screen on (not pulsing)");
+            mEmergencyCallStats.dump(pw, "Emergency call");
+            for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
+                final String reason = DozeEvent.reasonToString(i);
+                mProxStats[i][0].dump(pw, "Proximity near (" + reason + ")");
+                mProxStats[i][1].dump(pw, "Proximity far (" + reason + ")");
             }
         }
     }
 
-    private static void log(String msg) {
-        synchronized (DozeLog.class) {
-            if (sMessages == null) return;
-            sTimes[sPosition] = System.currentTimeMillis();
-            sMessages[sPosition] = msg;
-            sPosition = (sPosition + 1) % SIZE;
-            sCount = Math.min(sCount + 1, SIZE);
-        }
-        if (DEBUG) Log.d(TAG, msg);
+    private boolean log(@DozeEvent.EventType int eventType) {
+        return log(eventType, "");
     }
 
-    public static void tracePulseDropped(Context context, boolean pulsePending,
-            DozeMachine.State state, boolean blocked) {
-        if (!ENABLED) return;
-        init(context);
-        log("pulseDropped pulsePending=" + pulsePending + " state="
-                + state + " blocked=" + blocked);
+    private boolean log(@DozeEvent.EventType int eventType, String msg) {
+        return super.log(new DozeEvent.DozeEventBuilder()
+                .setType(eventType)
+                .setReason(msg)
+                .build());
     }
 
-    public static void tracePulseDropped(Context context, String why) {
-        if (!ENABLED) return;
-        init(context);
-        log("pulseDropped why=" + why);
+    /**
+     * Appends pulse dropped event to logs
+     */
+    public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) {
+        log(DozeEvent.PULSE_DROPPED, "pulsePending=" + pulsePending + " state="
+                + state.name() + " blocked=" + blocked);
     }
 
-    public static void tracePulseTouchDisabledByProx(Context context, boolean disabled) {
-        if (!ENABLED) return;
-        init(context);
-        log("pulseTouchDisabledByProx " + disabled);
+    /**
+     * Appends pulse dropped event to logs
+     * @param reason why the pulse was dropped
+     */
+    public void tracePulseDropped(String reason) {
+        log(DozeEvent.PULSE_DROPPED, "why=" + reason);
     }
 
-    public static void setRegisterKeyguardCallback(boolean registerKeyguardCallback) {
-        if (!ENABLED) return;
-        synchronized (DozeLog.class) {
-            if (sRegisterKeyguardCallback != registerKeyguardCallback && sMessages != null) {
-                throw new IllegalStateException("Cannot change setRegisterKeyguardCallback "
-                        + "after init()");
-            }
-            sRegisterKeyguardCallback = registerKeyguardCallback;
-        }
+    /**
+     * Appends pulse touch displayed by prox sensor event to logs
+     * @param disabled
+     */
+    public void tracePulseTouchDisabledByProx(boolean disabled) {
+        log(DozeEvent.PULSE_DISABLED_BY_PROX, "disabled=" + disabled);
     }
 
-    public static void traceSensor(Context context, int reason) {
-        if (!ENABLED) return;
-        init(context);
-        log("sensor type=" + reasonToString(reason));
+    /**
+     * Appends sensor triggered event to logs
+     * @param reason why the sensor was triggered
+     */
+    public void traceSensor(@DozeEvent.Reason int reason) {
+        log(DozeEvent.SENSOR_TRIGGERED, "type=" + DozeEvent.reasonToString(reason));
     }
 
-    private static class SummaryStats {
+    private class SummaryStats {
         private int mCount;
 
         public void append() {
@@ -305,7 +307,7 @@
             pw.print(": n=");
             pw.print(mCount);
             pw.print(" (");
-            final double perHr = (double) mCount / (System.currentTimeMillis() - sSince)
+            final double perHr = (double) mCount / (System.currentTimeMillis() - mSince)
                     * 1000 * 60 * 60;
             pw.print(perHr);
             pw.print("/hr)");
@@ -313,7 +315,7 @@
         }
     }
 
-    private static final KeyguardUpdateMonitorCallback sKeyguardCallback =
+    private final KeyguardUpdateMonitorCallback mKeyguardCallback =
             new KeyguardUpdateMonitorCallback() {
         @Override
         public void onEmergencyCallAction() {
@@ -340,4 +342,7 @@
             traceKeyguard(showing);
         }
     };
+
+    private static final int MAX_DOZE_DEBUG_LOGS = 400;
+    private static final int MAX_DOZE_LOGS = 50;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 93a51cc..75b1d6c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -27,6 +27,7 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.wakelock.WakeLock;
 
@@ -45,6 +46,7 @@
 
     static final String TAG = "DozeMachine";
     static final boolean DEBUG = DozeService.DEBUG;
+    private final DozeLog mDozeLog;
     private static final String REASON_CHANGE_STATE = "DozeMachine#requestState";
     private static final String REASON_HELD_FOR_STATE = "DozeMachine#heldForState";
 
@@ -121,6 +123,7 @@
     private final WakeLock mWakeLock;
     private final AmbientDisplayConfiguration mConfig;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
+    private final BatteryController mBatteryController;
     private Part[] mParts;
 
     private final ArrayList<State> mQueuedRequests = new ArrayList<>();
@@ -129,11 +132,14 @@
     private boolean mWakeLockHeldForCurrentState = false;
 
     public DozeMachine(Service service, AmbientDisplayConfiguration config,
-            WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle) {
+            WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
+            BatteryController batteryController, DozeLog dozeLog) {
         mDozeService = service;
         mConfig = config;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mWakeLock = wakeLock;
+        mBatteryController = batteryController;
+        mDozeLog = dozeLog;
     }
 
     /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
@@ -155,7 +161,7 @@
     @MainThread
     public void requestState(State requestedState) {
         Preconditions.checkArgument(requestedState != State.DOZE_REQUEST_PULSE);
-        requestState(requestedState, DozeLog.PULSE_REASON_NONE);
+        requestState(requestedState, DozeEvent.PULSE_REASON_NONE);
     }
 
     @MainThread
@@ -243,7 +249,7 @@
         State oldState = mState;
         mState = newState;
 
-        DozeLog.traceState(newState);
+        mDozeLog.traceState(newState);
         Trace.traceCounter(Trace.TRACE_TAG_APP, "doze_machine_state", newState.ordinal());
 
         updatePulseReason(newState, oldState, pulseReason);
@@ -257,7 +263,7 @@
         if (newState == State.DOZE_REQUEST_PULSE) {
             mPulseReason = pulseReason;
         } else if (oldState == State.DOZE_PULSE_DONE) {
-            mPulseReason = DozeLog.PULSE_REASON_NONE;
+            mPulseReason = DozeEvent.PULSE_REASON_NONE;
         }
     }
 
@@ -316,6 +322,9 @@
             Log.i(TAG, "Dropping pulse done because current state is already done: " + mState);
             return mState;
         }
+        if (requestedState == State.DOZE_AOD && mBatteryController.isAodPowerSave()) {
+            return State.DOZE;
+        }
         if (requestedState == State.DOZE_REQUEST_PULSE && !mState.canPulse()) {
             Log.i(TAG, "Dropping pulse request because current state can't pulse: " + mState);
             return mState;
@@ -349,7 +358,7 @@
                     nextState = State.DOZE;
                 }
 
-                transitionTo(nextState, DozeLog.PULSE_REASON_NONE);
+                transitionTo(nextState, DozeEvent.PULSE_REASON_NONE);
                 break;
             default:
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index a201400..7d86028 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -80,7 +80,8 @@
 
     public DozeSensors(Context context, AlarmManager alarmManager, AsyncSensorManager sensorManager,
             DozeParameters dozeParameters, AmbientDisplayConfiguration config, WakeLock wakeLock,
-            Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) {
+            Callback callback, Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy,
+            DozeLog dozeLog) {
         mContext = context;
         mAlarmManager = alarmManager;
         mSensorManager = sensorManager;
@@ -97,52 +98,59 @@
                         mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
                         null /* setting */,
                         dozeParameters.getPulseOnSigMotion(),
-                        DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */,
-                        false /* touchscreen */),
+                        DozeEvent.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */,
+                        false /* touchscreen */, dozeLog),
                 mPickupSensor = new TriggerSensor(
                         mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
                         Settings.Secure.DOZE_PICK_UP_GESTURE,
                         true /* settingDef */,
                         config.dozePickupSensorAvailable(),
-                        DozeLog.REASON_SENSOR_PICKUP, false /* touchCoords */,
+                        DozeEvent.REASON_SENSOR_PICKUP, false /* touchCoords */,
                         false /* touchscreen */,
-                        false /* ignoresSetting */),
+                        false /* ignoresSetting */,
+                        dozeLog),
                 new TriggerSensor(
                         findSensorWithType(config.doubleTapSensorType()),
                         Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
                         true /* configured */,
-                        DozeLog.REASON_SENSOR_DOUBLE_TAP,
+                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
                         dozeParameters.doubleTapReportsTouchCoordinates(),
-                        true /* touchscreen */),
+                        true /* touchscreen */,
+                        dozeLog),
                 new TriggerSensor(
                         findSensorWithType(config.tapSensorType()),
                         Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
                         true /* configured */,
-                        DozeLog.REASON_SENSOR_TAP,
+                        DozeEvent.REASON_SENSOR_TAP,
                         false /* reports touch coordinates */,
-                        true /* touchscreen */),
+                        true /* touchscreen */,
+                        dozeLog),
                 new TriggerSensor(
                         findSensorWithType(config.longPressSensorType()),
                         Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
                         false /* settingDef */,
                         true /* configured */,
-                        DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
+                        DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS,
                         true /* reports touch coordinates */,
-                        true /* touchscreen */),
+                        true /* touchscreen */,
+                        dozeLog),
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_DISPLAY),
                         Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
                         mConfig.wakeScreenGestureAvailable() && alwaysOn,
-                        DozeLog.REASON_SENSOR_WAKE_UP,
+                        DozeEvent.REASON_SENSOR_WAKE_UP,
                         false /* reports touch coordinates */,
-                        false /* touchscreen */),
+                        false /* touchscreen */,
+                        dozeLog),
                 new PluginSensor(
                         new SensorManagerPlugin.Sensor(TYPE_WAKE_LOCK_SCREEN),
                         Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
                         mConfig.wakeScreenGestureAvailable(),
-                        DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
+                        DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
                         false /* reports touch coordinates */,
-                        false /* touchscreen */, mConfig.getWakeLockScreenDebounce()),
+                        false /* touchscreen */,
+                        mConfig.getWakeLockScreenDebounce(),
+                        dozeLog),
         };
 
         mProximitySensor = new ProximitySensor(context, sensorManager);
@@ -306,23 +314,24 @@
         protected boolean mRegistered;
         protected boolean mDisabled;
         protected boolean mIgnoresSetting;
+        protected final DozeLog mDozeLog;
 
         public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
-                boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+                boolean reportsTouchCoordinates, boolean requiresTouchscreen, DozeLog dozeLog) {
             this(sensor, setting, true /* settingDef */, configured, pulseReason,
-                    reportsTouchCoordinates, requiresTouchscreen);
+                    reportsTouchCoordinates, requiresTouchscreen, dozeLog);
         }
 
         public TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
-                boolean requiresTouchscreen) {
+                boolean requiresTouchscreen, DozeLog dozeLog) {
             this(sensor, setting, settingDef, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen, false /* ignoresSetting */);
+                    requiresTouchscreen, false /* ignoresSetting */, dozeLog);
         }
 
         private TriggerSensor(Sensor sensor, String setting, boolean settingDef,
                 boolean configured, int pulseReason, boolean reportsTouchCoordinates,
-                boolean requiresTouchscreen, boolean ignoresSetting) {
+                boolean requiresTouchscreen, boolean ignoresSetting, DozeLog dozeLog) {
             mSensor = sensor;
             mSetting = setting;
             mSettingDefault = settingDef;
@@ -331,6 +340,7 @@
             mReportsTouchCoordinates = reportsTouchCoordinates;
             mRequiresTouchscreen = requiresTouchscreen;
             mIgnoresSetting = ignoresSetting;
+            mDozeLog = dozeLog;
         }
 
         public void setListening(boolean listen) {
@@ -387,7 +397,7 @@
         @Override
         @AnyThread
         public void onTrigger(TriggerEvent event) {
-            DozeLog.traceSensor(mContext, mPulseReason);
+            mDozeLog.traceSensor(mPulseReason);
             mHandler.post(mWakeLock.wrap(() -> {
                 if (DEBUG) Log.d(TAG, "onTrigger: " + triggerEventToString(event));
                 if (mSensor != null && mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
@@ -443,16 +453,17 @@
         private long mDebounce;
 
         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
-                int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen) {
+                int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
+                DozeLog dozeLog) {
             this(sensor, setting, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen, 0L /* debounce */);
+                    requiresTouchscreen, 0L /* debounce */, dozeLog);
         }
 
         PluginSensor(SensorManagerPlugin.Sensor sensor, String setting, boolean configured,
                 int pulseReason, boolean reportsTouchCoordinates, boolean requiresTouchscreen,
-                long debounce) {
+                long debounce, DozeLog dozeLog) {
             super(null, setting, configured, pulseReason, reportsTouchCoordinates,
-                    requiresTouchscreen);
+                    requiresTouchscreen, dozeLog);
             mPluginSensor = sensor;
             mDebounce = debounce;
         }
@@ -498,7 +509,7 @@
 
         @Override
         public void onSensorChanged(SensorManagerPlugin.SensorEvent event) {
-            DozeLog.traceSensor(mContext, mPulseReason);
+            mDozeLog.traceSensor(mPulseReason);
             mHandler.post(mWakeLock.wrap(() -> {
                 final long now = SystemClock.uptimeMillis();
                 if (now < mDebounceFrom + mDebounce) {
@@ -515,7 +526,7 @@
 
         /**
          * Called when a sensor requests a pulse
-         * @param pulseReason Requesting sensor, e.g. {@link DozeLog#REASON_SENSOR_PICKUP}
+         * @param pulseReason Requesting sensor, e.g. {@link DozeEvent#REASON_SENSOR_PICKUP}
          * @param screenX the location on the screen where the sensor fired or -1
          *                if the sensor doesn't support reporting screen locations.
          * @param screenY the location on the screen where the sensor fired or -1
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index e92acfc..17559c9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -39,15 +39,17 @@
     private static final String TAG = "DozeService";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     private final FalsingManager mFalsingManager;
+    private final DozeLog mDozeLog;
 
     private DozeMachine mDozeMachine;
     private DozeServicePlugin mDozePlugin;
     private PluginManager mPluginManager;
 
     @Inject
-    public DozeService(FalsingManager falsingManager) {
+    public DozeService(FalsingManager falsingManager, DozeLog dozeLog) {
         setDebug(DEBUG);
         mFalsingManager = falsingManager;
+        mDozeLog = dozeLog;
     }
 
     @Override
@@ -62,7 +64,7 @@
         }
         mPluginManager = Dependency.get(PluginManager.class);
         mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
-        mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager);
+        mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager, mDozeLog);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 8eed71c..b212884 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -67,6 +67,7 @@
 
     private final Context mContext;
     private final DozeMachine mMachine;
+    private final DozeLog mDozeLog;
     private final DozeSensors mDozeSensors;
     private final DozeHost mDozeHost;
     private final AmbientDisplayConfiguration mConfig;
@@ -89,7 +90,8 @@
             AlarmManager alarmManager, AmbientDisplayConfiguration config,
             DozeParameters dozeParameters, AsyncSensorManager sensorManager, Handler handler,
             WakeLock wakeLock, boolean allowPulseTriggers, DockManager dockManager,
-            ProximitySensor proximitySensor) {
+            ProximitySensor proximitySensor,
+            DozeLog dozeLog) {
         mContext = context;
         mMachine = machine;
         mDozeHost = dozeHost;
@@ -100,10 +102,11 @@
         mAllowPulseTriggers = allowPulseTriggers;
         mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
                 config, wakeLock, this::onSensor, this::onProximityFar,
-                dozeParameters.getPolicy());
+                dozeParameters.getPolicy(), dozeLog);
         mUiModeManager = mContext.getSystemService(UiModeManager.class);
         mDockManager = dockManager;
         mProxCheck = new ProximitySensor.ProximityCheck(proximitySensor, handler);
+        mDozeLog = dozeLog;
     }
 
     private void onNotification(Runnable onPulseSuppressedListener) {
@@ -113,18 +116,18 @@
         if (!sWakeDisplaySensorState) {
             Log.d(TAG, "Wake display false. Pulse denied.");
             runIfNotNull(onPulseSuppressedListener);
-            DozeLog.tracePulseDropped(mContext, "wakeDisplaySensor");
+            mDozeLog.tracePulseDropped("wakeDisplaySensor");
             return;
         }
         mNotificationPulseTime = SystemClock.elapsedRealtime();
         if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
             runIfNotNull(onPulseSuppressedListener);
-            DozeLog.tracePulseDropped(mContext, "pulseOnNotificationsDisabled");
+            mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
             return;
         }
-        requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
+        requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
                 onPulseSuppressedListener);
-        DozeLog.traceNotificationPulse(mContext);
+        mDozeLog.traceNotificationPulse();
     }
 
     private static void runIfNotNull(Runnable runnable) {
@@ -145,8 +148,7 @@
             final long start = SystemClock.uptimeMillis();
             mProxCheck.check(PROXIMITY_TIMEOUT_DELAY_MS, near -> {
                 final long end = SystemClock.uptimeMillis();
-                DozeLog.traceProximityResult(
-                        mContext,
+                mDozeLog.traceProximityResult(
                         near == null ? false : near,
                         end - start,
                         reason);
@@ -159,12 +161,12 @@
 
     @VisibleForTesting
     void onSensor(int pulseReason, float screenX, float screenY, float[] rawValues) {
-        boolean isDoubleTap = pulseReason == DozeLog.REASON_SENSOR_DOUBLE_TAP;
-        boolean isTap = pulseReason == DozeLog.REASON_SENSOR_TAP;
-        boolean isPickup = pulseReason == DozeLog.REASON_SENSOR_PICKUP;
-        boolean isLongPress = pulseReason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS;
-        boolean isWakeDisplay = pulseReason == DozeLog.REASON_SENSOR_WAKE_UP;
-        boolean isWakeLockScreen = pulseReason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
+        boolean isDoubleTap = pulseReason == DozeEvent.REASON_SENSOR_DOUBLE_TAP;
+        boolean isTap = pulseReason == DozeEvent.REASON_SENSOR_TAP;
+        boolean isPickup = pulseReason == DozeEvent.REASON_SENSOR_PICKUP;
+        boolean isLongPress = pulseReason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS;
+        boolean isWakeDisplay = pulseReason == DozeEvent.REASON_SENSOR_WAKE_UP;
+        boolean isWakeLockScreen = pulseReason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
         boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
 
         if (isWakeDisplay) {
@@ -201,7 +203,7 @@
                     SystemClock.elapsedRealtime() - mNotificationPulseTime;
             final boolean withinVibrationThreshold =
                     timeSinceNotification < mDozeParameters.getPickupVibrationThreshold();
-            DozeLog.tracePickupWakeUp(mContext, withinVibrationThreshold);
+            mDozeLog.tracePickupWakeUp(withinVibrationThreshold);
         }
     }
 
@@ -263,7 +265,7 @@
      *              transitions.
      */
     private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) {
-        DozeLog.traceWakeDisplay(wake);
+        mDozeLog.traceWakeDisplay(wake);
         sWakeDisplaySensorState = wake;
 
         if (wake) {
@@ -277,9 +279,9 @@
                     // Logs AOD open due to sensor wake up.
                     mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
                             .setType(MetricsEvent.TYPE_OPEN)
-                            .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
+                            .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP));
                 }
-            }, true /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
+            }, true /* alreadyPerformedProxCheck */, DozeEvent.REASON_SENSOR_WAKE_UP);
         } else {
             boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
             boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
@@ -288,7 +290,7 @@
                 // Logs AOD close due to sensor wake up.
                 mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
                         .setType(MetricsEvent.TYPE_CLOSE)
-                        .setSubtype(DozeLog.REASON_SENSOR_WAKE_UP));
+                        .setSubtype(DozeEvent.REASON_SENSOR_WAKE_UP));
             }
         }
     }
@@ -346,7 +348,6 @@
 
     private void checkTriggersAtInit() {
         if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
-                || mDozeHost.isPowerSaveActive()
                 || mDozeHost.isBlockingDoze()
                 || !mDozeHost.isProvisioned()) {
             mMachine.requestState(DozeMachine.State.FINISH);
@@ -361,14 +362,14 @@
         // When already pulsing we're allowed to show the wallpaper directly without
         // requesting a new pulse.
         if (mMachine.getState() == DozeMachine.State.DOZE_PULSING
-                && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+                && reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
             mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT);
             return;
         }
 
         if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
             if (mAllowPulseTriggers) {
-                DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
+                mDozeLog.tracePulseDropped(mPulsePending, mMachine.getState(),
                         mDozeHost.isPulsingBlocked());
             }
             runIfNotNull(onPulseSuppressedListener);
@@ -379,7 +380,7 @@
         proximityCheckThenCall((result) -> {
             if (result != null && result) {
                 // in pocket, abort pulse
-                DozeLog.tracePulseDropped(mContext, "inPocket");
+                mDozeLog.tracePulseDropped("inPocket");
                 mPulsePending = false;
                 runIfNotNull(onPulseSuppressedListener);
             } else {
@@ -401,7 +402,7 @@
     private void continuePulseRequest(int reason) {
         mPulsePending = false;
         if (mDozeHost.isPulsingBlocked() || !canPulse()) {
-            DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
+            mDozeLog.tracePulseDropped(mPulsePending, mMachine.getState(),
                     mDozeHost.isPulsingBlocked());
             return;
         }
@@ -425,7 +426,7 @@
         public void onReceive(Context context, Intent intent) {
             if (PULSE_ACTION.equals(intent.getAction())) {
                 if (DozeMachine.DEBUG) Log.d(TAG, "Received pulse intent");
-                requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
+                requestPulse(DozeEvent.PULSE_REASON_INTENT, false, /* performedProxCheck */
                         null /* onPulseSupressedListener */);
             }
             if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
@@ -482,8 +483,8 @@
 
         @Override
         public void onPowerSaveChanged(boolean active) {
-            if (active) {
-                mMachine.requestState(DozeMachine.State.FINISH);
+            if (mDozeHost.isPowerSaveActive()) {
+                mMachine.requestState(DozeMachine.State.DOZE);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 1f33af8..2c0ccd21 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -49,6 +49,7 @@
     private final AlarmTimeout mTimeTicker;
     private final boolean mCanAnimateTransition;
     private final DozeParameters mDozeParameters;
+    private final DozeLog mDozeLog;
 
     private boolean mKeyguardShowing;
     private final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
@@ -65,7 +66,8 @@
 
     public DozeUi(Context context, AlarmManager alarmManager, DozeMachine machine,
             WakeLock wakeLock, DozeHost host, Handler handler,
-            DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor) {
+            DozeParameters params, KeyguardUpdateMonitor keyguardUpdateMonitor,
+            DozeLog dozeLog) {
         mContext = context;
         mMachine = machine;
         mWakeLock = wakeLock;
@@ -75,6 +77,7 @@
         mDozeParameters = params;
         mTimeTicker = new AlarmTimeout(alarmManager, this::onTimeTick, "doze_time_tick", handler);
         keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
+        mDozeLog = dozeLog;
     }
 
     /**
@@ -83,7 +86,8 @@
      */
     private void updateAnimateScreenOff() {
         if (mCanAnimateTransition) {
-            final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing;
+            final boolean controlScreenOff = mDozeParameters.getAlwaysOn() && mKeyguardShowing
+                    && !mHost.isPowerSaveActive();
             mDozeParameters.setControlScreenOffAnimation(controlScreenOff);
             mHost.setAnimateScreenOff(controlScreenOff);
         }
@@ -96,7 +100,7 @@
                     public void onPulseStarted() {
                         try {
                             mMachine.requestState(
-                                    reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+                                    reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
                                             ? DozeMachine.State.DOZE_PULSING_BRIGHT
                                             : DozeMachine.State.DOZE_PULSING);
                         } catch (IllegalStateException e) {
@@ -175,7 +179,7 @@
         long delta = roundToNextMinute(time) - System.currentTimeMillis();
         boolean scheduled = mTimeTicker.schedule(delta, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
         if (scheduled) {
-            DozeLog.traceTimeTickScheduled(time, time + delta);
+            mDozeLog.traceTimeTickScheduled(time, time + delta);
         }
         mLastTimeTickElapsed = SystemClock.elapsedRealtime();
     }
@@ -192,7 +196,7 @@
         long millisSinceLastTick = SystemClock.elapsedRealtime() - mLastTimeTickElapsed;
         if (millisSinceLastTick > TIME_TICK_DEADLINE_MILLIS) {
             String delay = Formatter.formatShortElapsedTime(mContext, millisSinceLastTick);
-            DozeLog.traceMissedTick(delay);
+            mDozeLog.traceMissedTick(delay);
             Log.e(DozeMachine.TAG, "Missed AOD time tick by " + delay);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
index 6b5a780..c6812a7 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/EglHelper.java
@@ -22,6 +22,7 @@
 import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
 import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
 import static android.opengl.EGL14.EGL_DEPTH_SIZE;
+import static android.opengl.EGL14.EGL_EXTENSIONS;
 import static android.opengl.EGL14.EGL_GREEN_SIZE;
 import static android.opengl.EGL14.EGL_NONE;
 import static android.opengl.EGL14.EGL_NO_CONTEXT;
@@ -41,6 +42,7 @@
 import static android.opengl.EGL14.eglGetError;
 import static android.opengl.EGL14.eglInitialize;
 import static android.opengl.EGL14.eglMakeCurrent;
+import static android.opengl.EGL14.eglQueryString;
 import static android.opengl.EGL14.eglSwapBuffers;
 import static android.opengl.EGL14.eglTerminate;
 
@@ -64,6 +66,7 @@
     private static final int EGL_CONTEXT_PRIORITY_LEVEL_IMG = 0x3100;
     private static final int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
     private static final boolean DEBUG = true;
+    private static final String EGL_IMG_CONTEXT_PRIORITY = "EGL_IMG_context_priority";
 
     private EGLDisplay mEglDisplay;
     private EGLConfig mEglConfig;
@@ -71,6 +74,7 @@
     private EGLSurface mEglSurface;
     private final int[] mEglVersion = new int[2];
     private boolean mEglReady;
+    private boolean mContextPrioritySupported;
 
     /**
      * Initialize EGL and prepare EglSurface.
@@ -106,10 +110,22 @@
             return false;
         }
 
+        mContextPrioritySupported = isContextPrioritySuppported();
+
         mEglReady = true;
         return true;
     }
 
+    private boolean isContextPrioritySuppported() {
+        String[] extensions = eglQueryString(mEglDisplay, EGL_EXTENSIONS).split(" ");
+        for (String extension : extensions) {
+            if (extension.equals(EGL_IMG_CONTEXT_PRIORITY)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private EGLConfig chooseEglConfig() {
         int[] configsCount = new int[1];
         EGLConfig[] configs = new EGLConfig[1];
@@ -202,8 +218,15 @@
             Log.d(TAG, "createEglContext start");
         }
 
-        int[] attrib_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2,
-                EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_LOW_IMG, EGL_NONE};
+        int[] attrib_list = new int[5];
+        int idx = 0;
+        attrib_list[idx++] = EGL_CONTEXT_CLIENT_VERSION;
+        attrib_list[idx++] = 2;
+        if (mContextPrioritySupported) {
+            attrib_list[idx++] = EGL_CONTEXT_PRIORITY_LEVEL_IMG;
+            attrib_list[idx++] = EGL_CONTEXT_PRIORITY_LOW_IMG;
+        }
+        attrib_list[idx++] = EGL_NONE;
         if (hasEglDisplay()) {
             mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list, 0);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/log/Event.java b/packages/SystemUI/src/com/android/systemui/log/Event.java
new file mode 100644
index 0000000..92862a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/Event.java
@@ -0,0 +1,67 @@
+/*
+ * 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.log;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Stores information about an event that occurred in SystemUI to be used for debugging and triage.
+ * Every event has a time stamp, log level and message.
+ * Events are stored in {@link SysuiLog} and can be printed in a dumpsys.
+ */
+public class Event {
+    public static final int UNINITIALIZED = -1;
+
+    @IntDef({ERROR, WARN, INFO, DEBUG, VERBOSE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Level {}
+    public static final int VERBOSE = 2;
+    public static final int DEBUG = 3;
+    public static final int INFO = 4;
+    public static final int WARN = 5;
+    public static final int ERROR = 6;
+
+    private long mTimestamp;
+    private @Level int mLogLevel = DEBUG;
+    protected String mMessage;
+
+    public Event(String message) {
+        mTimestamp = System.currentTimeMillis();
+        mMessage = message;
+    }
+
+    public Event(@Level int logLevel, String message) {
+        mTimestamp = System.currentTimeMillis();
+        mLogLevel = logLevel;
+        mMessage = message;
+    }
+
+    public String getMessage() {
+        return mMessage;
+    }
+
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
+    public @Level int getLogLevel() {
+        return mLogLevel;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/RichEvent.java b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
new file mode 100644
index 0000000..89b7a818
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/RichEvent.java
@@ -0,0 +1,107 @@
+/*
+ * 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.log;
+
+/**
+ * Stores information about an event that occurred in SystemUI to be used for debugging and triage.
+ * Every rich event has a time stamp, event type, and log level, with the option to provide the
+ * reason this event was triggered.
+ * Events are stored in {@link SysuiLog} and can be printed in a dumpsys.
+ */
+public abstract class RichEvent extends Event {
+    private final int mType;
+    private final String mReason;
+
+    /**
+     * Create a rich event that includes an event type that matches with an index in the array
+     * getEventLabels().
+     */
+    public RichEvent(@Event.Level int logLevel, int type, String reason) {
+        super(logLevel, null);
+        final int numEvents = getEventLabels().length;
+        if (type < 0 || type >= numEvents) {
+            throw new IllegalArgumentException("Unsupported event type. Events only supported"
+                    + " from 0 to " + (numEvents - 1) + ", but given type=" + type);
+        }
+        mType = type;
+        mReason = reason;
+        mMessage = getEventLabels()[mType] + " " + mReason;
+    }
+
+    /**
+     * Returns an array of the event labels.  The index represents the event type and the
+     * corresponding String stored at that index is the user-readable representation of that event.
+     * @return array of user readable events, where the index represents its event type constant
+     */
+    public abstract String[] getEventLabels();
+
+    public int getType() {
+        return mType;
+    }
+
+    public String getReason() {
+        return mReason;
+    }
+
+    /**
+     * Builder to build a RichEvent.
+     * @param <B> Log specific builder that is extending this builder
+     */
+    public abstract static class Builder<B extends Builder<B>> {
+        public static final int UNINITIALIZED = -1;
+
+        private B mBuilder = getBuilder();
+        protected int mType = UNINITIALIZED;
+        protected String mReason;
+        protected @Level int mLogLevel;
+
+        /**
+         * Get the log-specific builder.
+         */
+        public abstract B getBuilder();
+
+        /**
+         * Build the log-specific event.
+         */
+        public abstract RichEvent build();
+
+        /**
+         * Optional - set the log level. Defaults to DEBUG.
+         */
+        public B setLogLevel(@Level int logLevel) {
+            mLogLevel = logLevel;
+            return mBuilder;
+        }
+
+        /**
+         * Required - set the event type.  These events must correspond with the events from
+         * getEventLabels().
+         */
+        public B setType(int type) {
+            mType = type;
+            return mBuilder;
+        }
+
+        /**
+         * Optional - set the reason why this event was triggered.
+         */
+        public B setReason(String reason) {
+            mReason = reason;
+            return mBuilder;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
new file mode 100644
index 0000000..a6e10e6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/SysuiLog.java
@@ -0,0 +1,163 @@
+/*
+ * 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.log;
+
+import android.os.Build;
+import android.os.SystemProperties;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
+import java.util.Locale;
+
+/**
+ * Thread-safe logger in SystemUI which prints logs to logcat and stores logs to be
+ * printed by the DumpController. This is an alternative to printing directly
+ * to avoid logs being deleted by chatty. The number of logs retained is varied based on
+ * whether the build is {@link Build.IS_DEBUGGABLE}.
+ *
+ * To manually view the logs via adb:
+ *      adb shell dumpsys activity service com.android.systemui/.SystemUIService \
+ *      dependency DumpController <SysuiLogId>
+ */
+public class SysuiLog implements Dumpable {
+    public static final SimpleDateFormat DATE_FORMAT =
+            new SimpleDateFormat("MM-dd HH:mm:ss", Locale.US);
+
+    private final Object mDataLock = new Object();
+    private final String mId;
+    private final int mMaxLogs;
+    private boolean mEnabled;
+
+    @VisibleForTesting protected ArrayDeque<Event> mTimeline;
+
+    /**
+     * Creates a SysuiLog
+     * To enable or disable logs, set the system property and then restart the device:
+     *      adb shell setprop sysui.log.enabled.<id> true/false && adb reboot
+     * @param dumpController where to register this logger's dumpsys
+     * @param id user-readable tag for this logger
+     * @param maxDebugLogs maximum number of logs to retain when {@link sDebuggable} is true
+     * @param maxLogs maximum number of logs to retain when {@link sDebuggable} is false
+     */
+    public SysuiLog(DumpController dumpController, String id, int maxDebugLogs, int maxLogs) {
+        this(dumpController, id, sDebuggable ? maxDebugLogs : maxLogs,
+                SystemProperties.getBoolean(SYSPROP_ENABLED_PREFIX + id, DEFAULT_ENABLED));
+    }
+
+    @VisibleForTesting
+    protected SysuiLog(DumpController dumpController, String id, int maxLogs, boolean enabled) {
+        mId = id;
+        mMaxLogs = maxLogs;
+        mEnabled = enabled;
+        mTimeline = mEnabled ? new ArrayDeque<>(mMaxLogs) : null;
+        dumpController.registerDumpable(mId, this);
+    }
+
+    public SysuiLog(DumpController dumpController, String id) {
+        this(dumpController, id, DEFAULT_MAX_DEBUG_LOGS, DEFAULT_MAX_LOGS);
+    }
+
+    /**
+     * Logs an event to the timeline which can be printed by the dumpsys.
+     * May also log to logcat if enabled.
+     * @return true if event was logged, else false
+     */
+    public boolean log(Event event) {
+        if (!mEnabled) {
+            return false;
+        }
+
+        synchronized (mDataLock) {
+            if (mTimeline.size() >= mMaxLogs) {
+                mTimeline.removeFirst();
+            }
+
+            mTimeline.add(event);
+        }
+
+        if (LOG_TO_LOGCAT_ENABLED) {
+            final String strEvent = eventToString(event);
+            switch (event.getLogLevel()) {
+                case Event.VERBOSE:
+                    Log.v(mId, strEvent);
+                    break;
+                case Event.DEBUG:
+                    Log.d(mId, strEvent);
+                    break;
+                case Event.ERROR:
+                    Log.e(mId, strEvent);
+                    break;
+                case Event.INFO:
+                    Log.i(mId, strEvent);
+                    break;
+                case Event.WARN:
+                    Log.w(mId, strEvent);
+                    break;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @return user-readable string of the given event
+     */
+    public String eventToString(Event event) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(SysuiLog.DATE_FORMAT.format(event.getTimestamp()));
+        sb.append(" ");
+        sb.append(event.getMessage());
+        return sb.toString();
+    }
+
+    /**
+     * only call on this method if you have the mDataLock
+     */
+    private void dumpTimelineLocked(PrintWriter pw) {
+        pw.println("\tTimeline:");
+
+        for (Event event : mTimeline) {
+            pw.println("\t" + eventToString(event));
+        }
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(mId + ":");
+
+        if (mEnabled) {
+            synchronized (mDataLock) {
+                dumpTimelineLocked(pw);
+            }
+        } else {
+            pw.print(" - Logging disabled.");
+        }
+    }
+
+    private static boolean sDebuggable = Build.IS_DEBUGGABLE;
+    private static final String SYSPROP_ENABLED_PREFIX = "sysui.log.enabled.";
+    private static final boolean LOG_TO_LOGCAT_ENABLED = sDebuggable;
+    private static final boolean DEFAULT_ENABLED = sDebuggable;
+    private static final int DEFAULT_MAX_DEBUG_LOGS = 100;
+    private static final int DEFAULT_MAX_LOGS = 50;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 4f2a6d8..5723afd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -247,6 +247,9 @@
     protected void onStop() {
         super.onStop();
 
+        // In cases such as device lock, hide and finish it so that it can be recreated on the top
+        // next time it starts, see also {@link #onUserLeaveHint}
+        hideMenu();
         cancelDelayedFinish();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 2542abd..bd3297b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -277,20 +277,7 @@
                     selectPosition(holder.getAdapterPosition(), v);
                 }
             });
-            if (mNeedsFocus) {
-                // Wait for this to get laid out then set its focus.
-                // Ensure that tile gets laid out so we get the callback.
-                holder.mTileView.requestLayout();
-                holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
-                    @Override
-                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                        holder.mTileView.removeOnLayoutChangeListener(this);
-                        holder.mTileView.requestFocus();
-                    }
-                });
-                mNeedsFocus = false;
-            }
+            focusOnHolder(holder);
             return;
         }
 
@@ -330,16 +317,38 @@
                         } else {
                             if (position < mEditIndex && canRemoveTiles()) {
                                 showAccessibilityDialog(position, v);
+                            } else if (position < mEditIndex && !canRemoveTiles()) {
+                                startAccessibleMove(position);
                             } else {
                                 startAccessibleAdd(position);
                             }
                         }
                     }
                 });
+                if (position == mAccessibilityFromIndex) {
+                    focusOnHolder(holder);
+                }
             }
         }
     }
 
+    private void focusOnHolder(Holder holder) {
+        if (mNeedsFocus) {
+            // Wait for this to get laid out then set its focus.
+            // Ensure that tile gets laid out so we get the callback.
+            holder.mTileView.requestLayout();
+            holder.mTileView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+                @Override
+                public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                    holder.mTileView.removeOnLayoutChangeListener(this);
+                    holder.mTileView.requestFocus();
+                }
+            });
+            mNeedsFocus = false;
+        }
+    }
+
     private boolean canRemoveTiles() {
         return mCurrentSpecs.size() > mMinNumTiles;
     }
@@ -396,6 +405,7 @@
         mAccessibilityFromIndex = position;
         mAccessibilityFromLabel = mTiles.get(position).state.label;
         mAccessibilityAction = ACTION_MOVE;
+        mNeedsFocus = true;
         notifyDataSetChanged();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 4de42cc..22470c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -95,6 +95,9 @@
 
     @Override
     public Intent getLongClickIntent() {
+        if (getState().state == Tile.STATE_UNAVAILABLE) {
+            return new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+        }
         return getCellularSettingIntent();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 2755e98..dafdd89 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -101,11 +101,15 @@
             state.slash = new SlashState();
         }
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
+        state.secondaryLabel = "";
         if (!mFlashlightController.isAvailable()) {
             state.icon = mIcon;
             state.slash.isSlashed = true;
+            state.secondaryLabel = mContext.getString(
+                    R.string.quick_settings_flashlight_camera_in_use);
             state.contentDescription = mContext.getString(
-                    R.string.accessibility_quick_settings_flashlight_unavailable);
+                    R.string.accessibility_quick_settings_flashlight_unavailable)
+                    + ", " + state.secondaryLabel;
             state.state = Tile.STATE_UNAVAILABLE;
             return;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0fc4fe7..a1b4a93 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -21,25 +21,30 @@
 import android.graphics.Rect;
 import android.provider.Settings;
 
-import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import javax.inject.Inject;
+
 /**
  * A proxy to a Recents implementation.
  */
 public class Recents extends SystemUI implements CommandQueue.Callbacks {
 
-    private RecentsImplementation mImpl;
+    private final RecentsImplementation mImpl;
+
+    @Inject
+    public Recents(RecentsImplementation impl) {
+        mImpl = impl;
+    }
 
     @Override
     public void start() {
         getComponent(CommandQueue.class).addCallback(this);
         putComponent(Recents.class, this);
-        mImpl = createRecentsImplementationFromConfig();
         mImpl.onStart(mContext, this);
     }
 
@@ -139,28 +144,6 @@
                 (Settings.Secure.getInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 0) != 0);
     }
 
-    /**
-     * @return The recents implementation from the config.
-     */
-    private RecentsImplementation createRecentsImplementationFromConfig() {
-        final String clsName = mContext.getString(R.string.config_recentsComponent);
-        if (clsName == null || clsName.length() == 0) {
-            throw new RuntimeException("No recents component configured", null);
-        }
-        Class<?> cls = null;
-        try {
-            cls = mContext.getClassLoader().loadClass(clsName);
-        } catch (Throwable t) {
-            throw new RuntimeException("Error loading recents component: " + clsName, t);
-        }
-        try {
-            RecentsImplementation impl = (RecentsImplementation) cls.newInstance();
-            return impl;
-        } catch (Throwable t) {
-            throw new RuntimeException("Error creating recents component: " + clsName, t);
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mImpl.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java
new file mode 100644
index 0000000..5555285
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsModule.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger injection module for {@link RecentsImplementation}
+ */
+@Module
+public class RecentsModule {
+    /**
+     * @return The {@link RecentsImplementation} from the config.
+     */
+    @Provides
+    public RecentsImplementation provideRecentsImpl(Context context) {
+        final String clsName = context.getString(R.string.config_recentsComponent);
+        if (clsName == null || clsName.length() == 0) {
+            throw new RuntimeException("No recents component configured", null);
+        }
+        Class<?> cls = null;
+        try {
+            cls = context.getClassLoader().loadClass(clsName);
+        } catch (Throwable t) {
+            throw new RuntimeException("Error loading recents component: " + clsName, t);
+        }
+        try {
+            RecentsImplementation impl = (RecentsImplementation) cls.newInstance();
+            return impl;
+        } catch (Throwable t) {
+            throw new RuntimeException("Error creating recents component: " + clsName, t);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 09f8045..16cdfaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -237,6 +237,7 @@
 
     /** @return {@link AssistHandleViewController} (only on the default display). */
     public AssistHandleViewController getAssistHandlerViewController() {
-        return getDefaultNavigationBarFragment().getAssistHandlerViewController();
+        NavigationBarFragment navBar = getDefaultNavigationBarFragment();
+        return navBar == null ? null : navBar.getAssistHandlerViewController();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index a70dc7c..e516af5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -27,7 +27,6 @@
 import android.view.MotionEvent
 import android.view.VelocityTracker
 import android.view.ViewConfiguration
-import com.android.systemui.Dependency
 
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.Interpolators
@@ -58,7 +57,8 @@
     private val bypassController: KeyguardBypassController,
     private val headsUpManager: HeadsUpManagerPhone,
     private val roundnessManager: NotificationRoundnessManager,
-    private val statusBarStateController: StatusBarStateController
+    private val statusBarStateController: StatusBarStateController,
+    private val falsingManager: FalsingManager
 ) : Gefingerpoken {
     companion object {
         private val RUBBERBAND_FACTOR_STATIC = 0.25f
@@ -99,7 +99,6 @@
     private val mTemp2 = IntArray(2)
     private var mDraggedFarEnough: Boolean = false
     private var mStartingChild: ExpandableView? = null
-    private val mFalsingManager: FalsingManager
     private var mPulsing: Boolean = false
     var isWakingToShadeLocked: Boolean = false
         private set
@@ -109,7 +108,7 @@
     private var velocityTracker: VelocityTracker? = null
 
     private val isFalseTouch: Boolean
-        get() = mFalsingManager.isFalseTouch
+        get() = falsingManager.isFalseTouch
     var qsExpanded: Boolean = false
     var pulseExpandAbortListener: Runnable? = null
     var bouncerShowing: Boolean = false
@@ -118,7 +117,6 @@
         mMinDragDistance = context.resources.getDimensionPixelSize(
                 R.dimen.keyguard_drag_down_min_distance)
         mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
-        mFalsingManager = Dependency.get(FalsingManager::class.java)
         mPowerManager = context.getSystemService(PowerManager::class.java)
     }
 
@@ -151,7 +149,7 @@
             MotionEvent.ACTION_MOVE -> {
                 val h = y - mInitialTouchY
                 if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
-                    mFalsingManager.onStartExpandingFromPulse()
+                    falsingManager.onStartExpandingFromPulse()
                     isExpanding = true
                     captureStartingChild(mInitialTouchX, mInitialTouchY)
                     mInitialTouchY = y
@@ -192,7 +190,7 @@
                 velocityTracker!!.computeCurrentVelocity(1000 /* units */)
                 val canExpand = moveDistance > 0 && velocityTracker!!.getYVelocity() > -1000 &&
                         statusBarStateController.state != StatusBarState.SHADE
-                if (!mFalsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
+                if (!falsingManager.isUnlockingDisabled && !isFalseTouch && canExpand) {
                     finishExpansion()
                 } else {
                     cancelExpansion()
@@ -297,7 +295,7 @@
 
     private fun cancelExpansion() {
         isExpanding = false
-        mFalsingManager.onExpansionFromPulseStopped()
+        falsingManager.onExpansionFromPulseStopped()
         if (mStartingChild != null) {
             reset(mStartingChild!!)
             mStartingChild = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 9362d2d..eadec6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import javax.inject.Inject;
@@ -63,6 +64,7 @@
     private final Context mContext;
     private final PowerManager mPowerManager;
     private final IDreamManager mDreamManager;
+    private final BatteryController mBatteryController;
 
     private NotificationPresenter mPresenter;
     private HeadsUpManager mHeadsUpManager;
@@ -75,13 +77,14 @@
 
     @Inject
     public NotificationInterruptionStateProvider(Context context, NotificationFilter filter,
-            StatusBarStateController stateController) {
+            StatusBarStateController stateController, BatteryController batteryController) {
         this(context,
                 (PowerManager) context.getSystemService(Context.POWER_SERVICE),
                 IDreamManager.Stub.asInterface(
                         ServiceManager.checkService(DreamService.DREAM_SERVICE)),
                 new AmbientDisplayConfiguration(context),
                 filter,
+                batteryController,
                 stateController);
     }
 
@@ -92,10 +95,12 @@
             IDreamManager dreamManager,
             AmbientDisplayConfiguration ambientDisplayConfiguration,
             NotificationFilter notificationFilter,
+            BatteryController batteryController,
             StatusBarStateController statusBarStateController) {
         mContext = context;
         mPowerManager = powerManager;
         mDreamManager = dreamManager;
+        mBatteryController = batteryController;
         mAmbientDisplayConfiguration = ambientDisplayConfiguration;
         mNotificationFilter = notificationFilter;
         mStatusBarStateController = statusBarStateController;
@@ -293,6 +298,13 @@
             return false;
         }
 
+        if (mBatteryController.isAodPowerSave()) {
+            if (DEBUG_HEADS_UP) {
+                Log.d(TAG, "No pulsing: disabled by battery saver: " + sbn.getKey());
+            }
+            return false;
+        }
+
         if (!canAlertCommon(entry)) {
             if (DEBUG_HEADS_UP) {
                 Log.d(TAG, "No pulsing: notification shouldn't alert: " + sbn.getKey());
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
new file mode 100644
index 0000000..2396d28
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java
@@ -0,0 +1,153 @@
+/*
+ * 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.logging;
+
+import android.annotation.IntDef;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.log.RichEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An event related to notifications. {@link NotifLog} stores and prints these events for debugging
+ * and triaging purposes.
+ */
+public class NotifEvent extends RichEvent {
+    public static final int TOTAL_EVENT_TYPES = 8;
+    private StatusBarNotification mSbn;
+    private Ranking mRanking;
+
+    /**
+     * Creates a NotifEvent with an event type that matches with an index in the array
+     * getSupportedEvents() and {@link EventType}.
+     *
+     * The status bar notification and ranking objects are stored as shallow copies of the current
+     * state of the event when this event occurred.
+     */
+    public NotifEvent(int logLevel, int type, String reason, StatusBarNotification sbn,
+            Ranking ranking) {
+        super(logLevel, type, reason);
+        mSbn = sbn.clone();
+        mRanking = new Ranking();
+        mRanking.populate(ranking);
+        mMessage += getExtraInfo();
+    }
+
+    private String getExtraInfo() {
+        StringBuilder extraInfo = new StringBuilder();
+
+        if (mSbn != null) {
+            extraInfo.append(" Sbn=");
+            extraInfo.append(mSbn);
+        }
+
+        if (mRanking != null) {
+            extraInfo.append(" Ranking=");
+            extraInfo.append(mRanking);
+        }
+
+        return extraInfo.toString();
+    }
+
+    /**
+     * Event labels for NotifEvents
+     * Index corresponds to the {@link EventType}
+     */
+    @Override
+    public String[] getEventLabels() {
+        final String[] events = new String[]{
+                "NotifAdded",
+                "NotifRemoved",
+                "NotifUpdated",
+                "HeadsUpStarted",
+                "HeadsUpEnded",
+                "Filter",
+                "Sort",
+                "NotifVisibilityChanged",
+        };
+
+        if (events.length != TOTAL_EVENT_TYPES) {
+            throw new IllegalStateException("NotifEvents events.length should match "
+                    + TOTAL_EVENT_TYPES
+                    + " events.length=" + events.length
+                    + " TOTAL_EVENT_LENGTH=" + TOTAL_EVENT_TYPES);
+        }
+        return events;
+    }
+
+    /**
+     * @return a copy of the status bar notification that changed with this event
+     */
+    public StatusBarNotification getSbn() {
+        return mSbn;
+    }
+
+    /**
+     * Builds a NotifEvent.
+     */
+    public static class NotifEventBuilder extends RichEvent.Builder<NotifEventBuilder> {
+        private StatusBarNotification mSbn;
+        private Ranking mRanking;
+
+        @Override
+        public NotifEventBuilder getBuilder() {
+            return this;
+        }
+
+        /**
+         * Stores the status bar notification object. A shallow copy is stored in the NotifEvent's
+         * constructor.
+         */
+        public NotifEventBuilder setSbn(StatusBarNotification sbn) {
+            mSbn = sbn;
+            return this;
+        }
+
+        /**
+         * Stores the ranking object. A shallow copy is stored in the NotifEvent's
+         * constructor.
+         */
+        public NotifEventBuilder setRanking(Ranking ranking) {
+            mRanking = ranking;
+            return this;
+        }
+
+        @Override
+        public RichEvent build() {
+            return new NotifEvent(mLogLevel, mType, mReason, mSbn, mRanking);
+        }
+    }
+
+    @IntDef({NOTIF_ADDED, NOTIF_REMOVED, NOTIF_UPDATED, HEADS_UP_STARTED, HEADS_UP_ENDED, FILTER,
+            SORT, NOTIF_VISIBILITY_CHANGED})
+    /**
+     * Types of NotifEvents
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EventType {}
+    public static final int NOTIF_ADDED = 0;
+    public static final int NOTIF_REMOVED = 1;
+    public static final int NOTIF_UPDATED = 2;
+    public static final int HEADS_UP_STARTED = 3;
+    public static final int HEADS_UP_ENDED = 4;
+    public static final int FILTER = 5;
+    public static final int SORT = 6;
+    public static final int NOTIF_VISIBILITY_CHANGED = 7;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
new file mode 100644
index 0000000..d42cd82
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifLog.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging;
+
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.StatusBarNotification;
+
+import com.android.systemui.DumpController;
+import com.android.systemui.log.SysuiLog;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Logs systemui notification events for debugging and triaging purposes. Logs are dumped in
+ * bugreports or on demand:
+ *      adb shell dumpsys activity service com.android.systemui/.SystemUIService \
+ *      dependency DumpController NotifLog
+ */
+@Singleton
+public class NotifLog extends SysuiLog {
+    private static final String TAG = "NotifLog";
+    private static final int MAX_DOZE_DEBUG_LOGS = 400;
+    private static final int MAX_DOZE_LOGS = 50;
+
+    @Inject
+    public NotifLog(DumpController dumpController) {
+        super(dumpController, TAG, MAX_DOZE_DEBUG_LOGS, MAX_DOZE_LOGS);
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a notification, ranking and message
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn,
+            Ranking ranking, String msg) {
+        return log(new NotifEvent.NotifEventBuilder()
+                .setType(eventType)
+                .setSbn(sbn)
+                .setRanking(ranking)
+                .setReason(msg)
+                .build());
+    }
+
+    /**
+     * Logs a {@link NotifEvent}
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType) {
+        return log(eventType, null, null, null);
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a message
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, String msg) {
+        return log(eventType, null, null, msg);
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a notification
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn) {
+        return log(eventType, sbn, null, "");
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a ranking
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, Ranking ranking) {
+        return log(eventType, null, ranking, "");
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a notification and ranking
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, StatusBarNotification sbn,
+            Ranking ranking) {
+        return log(eventType, sbn, ranking, "");
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a notification entry
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry) {
+        return log(eventType, entry.sbn(), entry.ranking(), "");
+    }
+
+    /**
+     * Logs a {@link NotifEvent} with a notification entry
+     * @return true if successfully logged, else false
+     */
+    public boolean log(@NotifEvent.EventType int eventType, NotificationEntry entry,
+            String msg) {
+        return log(eventType, entry.sbn(), entry.ranking(), msg);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index 8d73251..a817f54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -180,6 +180,10 @@
         initDimens();
     }
 
+    public FalsingManager getFalsingManager() {
+        return mFalsingManager;
+    }
+
     private void updateColors() {
         mNormalColor = mContext.getColor(R.color.notification_material_background_color);
         mTintedRippleColor = mContext.getColor(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 0f6ce21..9f4b026 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -74,7 +74,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
@@ -221,7 +220,6 @@
     private ViewStub mGutsStub;
     private boolean mIsSystemChildExpanded;
     private boolean mIsPinned;
-    private FalsingManager mFalsingManager;
     private boolean mExpandAnimationRunning;
     private AboveShelfChangedListener mAboveShelfChangedListener;
     private HeadsUpManager mHeadsUpManager;
@@ -1636,7 +1634,6 @@
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mFalsingManager = Dependency.get(FalsingManager.class);  // TODO: inject into a controller.
         mNotificationInflater = new NotificationContentInflater(this);
         mMenuRow = new NotificationMenuRow(mContext);
         mImageResolver = new NotificationInlineImageResolver(context,
@@ -2208,7 +2205,7 @@
      * @param allowChildExpansion whether a call to this method allows expanding children
      */
     public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
-        mFalsingManager.setNotificationExpanded();
+        getFalsingManager().setNotificationExpanded();
         if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
                 && !mChildrenContainer.showingAsLowPriority()) {
             final boolean wasExpanded = mGroupManager.isGroupExpanded(mStatusBarNotification);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index 4700baa..18d436f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -421,7 +421,7 @@
     }
 
     /** Listener for animations executed in {@link #animateClose(int, int, boolean)}. */
-    private static class AnimateCloseListener extends AnimatorListenerAdapter {
+    private class AnimateCloseListener extends AnimatorListenerAdapter {
         final View mView;
         private final GutsContent mGutsContent;
 
@@ -433,8 +433,10 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             super.onAnimationEnd(animation);
-            mView.setVisibility(View.GONE);
-            mGutsContent.onFinishedClosing();
+            if (!isExposed()) {
+                mView.setVisibility(View.GONE);
+                mGutsContent.onFinishedClosing();
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 9d0dd6b..2b7deec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -100,6 +100,7 @@
     protected String mKeyToRemoveOnGutsClosed;
 
     private StatusBar mStatusBar;
+    private Runnable mOpenRunnable;
 
     @Inject
     public NotificationGutsManager(
@@ -343,6 +344,7 @@
     public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls,
             int x, int y, boolean resetMenu) {
         if (mNotificationGutsExposed != null) {
+            mNotificationGutsExposed.removeCallbacks(mOpenRunnable);
             mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force);
         }
         if (resetMenu) {
@@ -445,7 +447,7 @@
         // ensure that it's laid but not visible until actually laid out
         guts.setVisibility(View.INVISIBLE);
         // Post to ensure the the guts are properly laid out.
-        guts.post(new Runnable() {
+        mOpenRunnable = new Runnable() {
             @Override
             public void run() {
                 if (row.getWindowToken() == null) {
@@ -470,7 +472,8 @@
                 mListContainer.onHeightChanged(row, true /* needsAnimation */);
                 mGutsMenuItem = menuItem;
             }
-        });
+        };
+        guts.post(mOpenRunnable);
         return true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 60e381a..fe3c04e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -22,11 +22,14 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
+import com.android.systemui.doze.DozeEvent;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 
+import javax.inject.Inject;
+
 /**
  * Controller which handles all the doze animations of the scrims.
  */
@@ -34,6 +37,7 @@
     private static final String TAG = "DozeScrimController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
+    private final DozeLog mDozeLog;
     private final DozeParameters mDozeParameters;
     private final Handler mHandler = new Handler();
 
@@ -47,7 +51,7 @@
         public void onDisplayBlanked() {
             if (DEBUG) {
                 Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
-                        + DozeLog.reasonToString(mPulseReason));
+                        + DozeEvent.reasonToString(mPulseReason));
             }
             if (!mDozing) {
                 return;
@@ -68,8 +72,8 @@
             // Notifications should time out on their own.  Pulses due to notifications should
             // instead be managed externally based off the notification's lifetime.
             // Dock also controls the time out by self.
-            if (mPulseReason != DozeLog.PULSE_REASON_NOTIFICATION
-                    && mPulseReason != DozeLog.PULSE_REASON_DOCKING) {
+            if (mPulseReason != DozeEvent.PULSE_REASON_NOTIFICATION
+                    && mPulseReason != DozeEvent.PULSE_REASON_DOCKING) {
                 mHandler.postDelayed(mPulseOut, mDozeParameters.getPulseVisibleDuration());
                 mHandler.postDelayed(mPulseOutExtended,
                         mDozeParameters.getPulseVisibleDurationExtended());
@@ -90,14 +94,16 @@
          */
         @Override
         public boolean shouldTimeoutWallpaper() {
-            return mPulseReason == DozeLog.PULSE_REASON_DOCKING;
+            return mPulseReason == DozeEvent.PULSE_REASON_DOCKING;
         }
     };
 
-    public DozeScrimController(DozeParameters dozeParameters) {
+    @Inject
+    public DozeScrimController(DozeParameters dozeParameters, DozeLog dozeLog) {
         mDozeParameters = dozeParameters;
         //Never expected to be destroyed
         Dependency.get(StatusBarStateController.class).addCallback(this);
+        mDozeLog = dozeLog;
     }
 
     @VisibleForTesting
@@ -168,14 +174,14 @@
     }
 
     private void pulseStarted() {
-        DozeLog.tracePulseStart(mPulseReason);
+        mDozeLog.tracePulseStart(mPulseReason);
         if (mPulseCallback != null) {
             mPulseCallback.onPulseStarted();
         }
     }
 
     private void pulseFinished() {
-        DozeLog.tracePulseFinish();
+        mDozeLog.tracePulseFinish();
         if (mPulseCallback != null) {
             mPulseCallback.onPulseFinished();
             mPulseCallback = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt
index 7dcc2fc..53601ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NPVPluginManager.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.view.View
+import android.view.ViewGroup.MarginLayoutParams
 import android.widget.FrameLayout
 import com.android.systemui.plugins.NPVPlugin
 import com.android.systemui.plugins.PluginListener
@@ -36,6 +37,7 @@
 
     private var plugin: NPVPlugin? = null
     private var animator = createAnimator()
+    private var yOffset = 0f
 
     private fun createAnimator() = TouchAnimator.Builder()
             .addFloat(parent, "alpha", 1f, 0f)
@@ -76,7 +78,7 @@
     }
 
     fun setExpansion(expansion: Float, headerTranslation: Float, heightDiff: Float) {
-        parent.setTranslationY(expansion * heightDiff + headerTranslation)
+        parent.setTranslationY(expansion * heightDiff + headerTranslation + yOffset)
         if (!expansion.isNaN()) animator.setPosition(expansion)
     }
 
@@ -88,5 +90,13 @@
         animator = createAnimator()
     }
 
-    fun getHeight() = if (plugin != null) parent.height else 0
+    fun getHeight() =
+        if (plugin != null) {
+            parent.height + (parent.getLayoutParams() as MarginLayoutParams).topMargin
+        } else 0
+
+    fun setYOffset(y: Float) {
+        yOffset = y
+        parent.setTranslationY(yOffset)
+    }
 }
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 86da10a..cee1d5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -68,6 +68,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.doze.DozeLog;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.FalsingManager;
@@ -459,8 +460,9 @@
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController,
             FalsingManager falsingManager,
-            PluginManager pluginManager) {
-        super(context, attrs);
+            PluginManager pluginManager,
+            DozeLog dozeLog) {
+        super(context, attrs, falsingManager, dozeLog);
         setWillNotDraw(!DEBUG);
         mInjectionInflationController = injectionInflationController;
         mFalsingManager = falsingManager;
@@ -652,8 +654,7 @@
             mNotificationStackScroller.setLayoutParams(lp);
         }
         int sideMargin = res.getDimensionPixelOffset(R.dimen.notification_side_paddings);
-        int topMargin =
-                res.getDimensionPixelOffset(com.android.internal.R.dimen.quick_qs_total_height);
+        int topMargin = sideMargin;
         lp = (FrameLayout.LayoutParams) mPluginFrame.getLayoutParams();
         if (lp.width != qsWidth || lp.gravity != panelGravity || lp.leftMargin != sideMargin
                 || lp.rightMargin != sideMargin || lp.topMargin != topMargin) {
@@ -796,6 +797,7 @@
         int oldMaxHeight = mQsMaxExpansionHeight;
         if (mQs != null) {
             mQsMinExpansionHeight = mKeyguardShowing ? 0 : mQs.getQsMinExpansionHeight();
+            mNPVPluginManager.setYOffset(mQsMinExpansionHeight);
             mQsMinExpansionHeight += mNPVPluginManager.getHeight();
             mQsMaxExpansionHeight = mQs.getDesiredHeight();
             mNotificationStackScroller.setMaxTopPadding(
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 ffaf3d5..432d636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -111,6 +111,7 @@
     private FlingAnimationUtils mFlingAnimationUtilsClosing;
     private FlingAnimationUtils mFlingAnimationUtilsDismissing;
     private final FalsingManager mFalsingManager;
+    private final DozeLog mDozeLog;
     private final VibratorHelper mVibratorHelper;
 
     /**
@@ -204,7 +205,8 @@
         mJustPeeked = true;
     }
 
-    public PanelView(Context context, AttributeSet attrs) {
+    public PanelView(Context context, AttributeSet attrs, FalsingManager falsingManager,
+            DozeLog dozeLog) {
         super(context, attrs);
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f /* maxLengthSeconds */,
                 0.6f /* speedUpFactor */);
@@ -214,7 +216,8 @@
                 0.5f /* maxLengthSeconds */, 0.2f /* speedUpFactor */, 0.6f /* x2 */,
                 0.84f /* y2 */);
         mBounceInterpolator = new BounceInterpolator();
-        mFalsingManager = Dependency.get(FalsingManager.class);  // TODO: inject into a controller.
+        mFalsingManager = falsingManager;
+        mDozeLog = dozeLog;
         mNotificationsDragEnabled =
                 getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
         mVibratorHelper = Dependency.get(VibratorHelper.class);
@@ -477,7 +480,7 @@
             boolean expand = flingExpands(vel, vectorVel, x, y)
                     || event.getActionMasked() == MotionEvent.ACTION_CANCEL
                     || forceCancel;
-            DozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
+            mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
                     mStatusBar.isFalsingThresholdNeeded(),
                     mStatusBar.isWakeUpComingFromTouch());
                     // Log collapse gesture if on lock screen.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index bd9ce3a..5ba19cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@
 import com.android.internal.util.function.TriConsumer;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
@@ -311,10 +312,12 @@
         // Docking pulses may take a long time, wallpapers should also fade away after a while.
         mWallpaperVisibilityTimedOut = false;
         if (shouldFadeAwayWallpaper()) {
-            mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
-                    AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+            DejankUtils.postAfterTraversal(() -> {
+                mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
+                        AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+            });
         } else {
-            mTimeTicker.cancel();
+            DejankUtils.postAfterTraversal(mTimeTicker::cancel);
         }
 
         if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
@@ -430,8 +433,10 @@
             // and docking.
             if (mWallpaperVisibilityTimedOut) {
                 mWallpaperVisibilityTimedOut = false;
-                mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
-                        AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+                DejankUtils.postAfterTraversal(() -> {
+                    mTimeTicker.schedule(mDozeParameters.getWallpaperAodDuration(),
+                            AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+                });
             }
         }
     }
@@ -754,6 +759,16 @@
     }
 
     private void onFinished(Callback callback) {
+        if (!hasReachedFinalState(mScrimBehind)
+            || !hasReachedFinalState(mScrimInFront)
+            || !hasReachedFinalState(mScrimForBubble)) {
+            if (callback != null && callback != mCallback) {
+                // Since we only notify the callback that we're finished once everything has
+                // finished, we need to make sure that any changing callbacks are also invoked
+                callback.onFinished();
+            }
+            return;
+        }
         if (mWakeLockHeld) {
             mWakeLock.release(TAG);
             mWakeLockHeld = false;
@@ -773,9 +788,17 @@
             mInFrontTint = Color.TRANSPARENT;
             mBehindTint = Color.TRANSPARENT;
             mBubbleTint = Color.TRANSPARENT;
+            updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
+            updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
+            updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
         }
     }
 
+    private boolean hasReachedFinalState(ScrimView scrim) {
+        return scrim.getViewAlpha() == getCurrentScrimAlpha(scrim)
+                && scrim.getTint() == getCurrentScrimTint(scrim);
+    }
+
     private boolean isAnimating(View scrim) {
         return scrim.getTag(TAG_KEY_ANIM) != null;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 7bab7f1..5fc2d9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -152,6 +152,7 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.doze.DozeEvent;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.doze.DozeReceiver;
@@ -370,6 +371,8 @@
 
     protected StatusBarIconController mIconController;
     @Inject
+    DozeLog mDozeLog;
+    @Inject
     InjectionInflationController mInjectionInflater;
     @Inject
     PulseExpansionHandler mPulseExpansionHandler;
@@ -393,6 +396,8 @@
     boolean mAllowNotificationLongPress;
     @Inject
     protected NotifPipelineInitializer mNotifPipelineInitializer;
+    @Inject
+    protected FalsingManager mFalsingManager;
 
     @VisibleForTesting
     BroadcastDispatcher mBroadcastDispatcher;
@@ -584,7 +589,6 @@
         }
     };
     private boolean mNoAnimationOnNextBarModeChange;
-    protected FalsingManager mFalsingManager;
     private final SysuiStatusBarStateController mStatusBarStateController =
             (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
 
@@ -716,7 +720,6 @@
         mRecents = getComponent(Recents.class);
 
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
-        mFalsingManager = Dependency.get(FalsingManager.class);
 
         // Connect in to the status bar manager service
         mCommandQueue = getComponent(CommandQueue.class);
@@ -968,7 +971,8 @@
                 mKeyguardStateController);
         mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
                 mHeadsUpManager, mNotificationIconAreaController, mScrimController);
-        mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context));
+        mDozeScrimController = new DozeScrimController(DozeParameters.getInstance(context),
+                mDozeLog);
 
         BackDropView backdrop = mStatusBarWindow.findViewById(R.id.backdrop);
         mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
@@ -2377,7 +2381,7 @@
         final boolean lightWpTheme = mContext.getThemeResId() == R.style.Theme_SystemUI_Light;
         pw.println("    light wallpaper theme: " + lightWpTheme);
 
-        DozeLog.dump(pw);
+        mDozeLog.dump(pw);
 
         if (mBiometricUnlockController != null) {
             mBiometricUnlockController.dump(pw);
@@ -2444,7 +2448,7 @@
             mKeyguardUpdateMonitor.dump(fd, pw, args);
         }
 
-        Dependency.get(FalsingManager.class).dump(pw);
+        mFalsingManager.dump(pw);
         FalsingLog.dump(pw);
 
         pw.println("SharedPreferences:");
@@ -4003,7 +4007,7 @@
         public void startDozing() {
             if (!mDozingRequested) {
                 mDozingRequested = true;
-                DozeLog.traceDozing(mContext, mDozing);
+                mDozeLog.traceDozing(mDozing);
                 updateDozing();
                 updateIsKeyguard();
             }
@@ -4011,22 +4015,22 @@
 
         @Override
         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
+            if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) {
                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                         "com.android.systemui:LONG_PRESS");
                 startAssist(new Bundle());
                 return;
             }
 
-            if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+            if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
                 mScrimController.setWakeLockScreenSensorActive(true);
             }
 
-            if (reason == DozeLog.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
+            if (reason == DozeEvent.PULSE_REASON_DOCKING && mStatusBarWindow != null) {
                 mStatusBarWindow.suppressWakeUpGesture(true);
             }
 
-            boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+            boolean passiveAuthInterrupt = reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
                             && mWakeLockScreenPerformsAuth;
             // Set the state to pulsing, so ScrimController will know what to do once we ask it to
             // execute the transition. The pulse callback will then be invoked when the scrims
@@ -4077,7 +4081,7 @@
         public void stopDozing() {
             if (mDozingRequested) {
                 mDozingRequested = false;
-                DozeLog.traceDozing(mContext, mDozing);
+                mDozeLog.traceDozing(mDozing);
                 updateDozing();
             }
         }
@@ -4085,7 +4089,7 @@
         @Override
         public void onIgnoreTouchWhilePulsing(boolean ignore) {
             if (ignore != mIgnoreTouchWhilePulsing) {
-                DozeLog.tracePulseTouchDisabledByProx(mContext, ignore);
+                mDozeLog.tracePulseTouchDisabledByProx(ignore);
             }
             mIgnoreTouchWhilePulsing = ignore;
             if (isDozing() && ignore) {
@@ -4129,7 +4133,7 @@
 
         @Override
         public void extendPulse(int reason) {
-            if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+            if (reason == DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
                 mScrimController.setWakeLockScreenSensorActive(true);
             }
             if (mDozeScrimController.isPulsing() && mHeadsUpManager.hasNotifications()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index df23f8ca..75b0cdc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -61,6 +61,8 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
+import androidx.annotation.VisibleForTesting;
+
 /**
  * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
  * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done,
@@ -160,6 +162,7 @@
     private boolean mLastLockVisible;
 
     private OnDismissAction mAfterKeyguardGoneAction;
+    private Runnable mKeyguardGoneCancelAction;
     private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>();
 
     // Dismiss action to be launched when we stop dozing or the keyguard is gone.
@@ -329,10 +332,20 @@
         return false;
     }
 
-    private void hideBouncer(boolean destroyView) {
+    @VisibleForTesting
+    void hideBouncer(boolean destroyView) {
         if (mBouncer == null) {
             return;
         }
+        if (mShowing) {
+            // If we were showing the bouncer and then aborting, we need to also clear out any
+            // potential actions unless we actually unlocked.
+            mAfterKeyguardGoneAction = null;
+            if (mKeyguardGoneCancelAction != null) {
+                mKeyguardGoneCancelAction.run();
+                mKeyguardGoneCancelAction = null;
+            }
+        }
         mBouncer.hide(destroyView);
         cancelPendingWakeupAction();
     }
@@ -365,6 +378,7 @@
                 mBouncer.showWithDismissAction(r, cancelAction);
             } else {
                 mAfterKeyguardGoneAction = r;
+                mKeyguardGoneCancelAction = cancelAction;
                 mBouncer.show(false /* resetSecuritySelection */);
             }
         }
@@ -672,6 +686,7 @@
             mAfterKeyguardGoneAction.onDismiss();
             mAfterKeyguardGoneAction = null;
         }
+        mKeyguardGoneCancelAction = null;
         for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) {
             mAfterKeyguardGoneRunnables.get(i).run();
         }
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 111cdd2..738d076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -45,9 +45,7 @@
     /**
      * Returns {@code true} if AOD was disabled by power saving policies.
      */
-    default boolean isAodPowerSave() {
-        return isPowerSave();
-    }
+    boolean isAodPowerSave();
 
     /**
      * A listener that will be notified whenever a change in battery level or power save mode has
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
new file mode 100644
index 0000000..d6d0a36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -0,0 +1,203 @@
+/*
+ * 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.tv;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+class AudioRecordingDisclosureBar {
+    private static final String TAG = "AudioRecordingDisclosureBar";
+    private static final boolean DEBUG = false;
+
+    private static final String LAYOUT_PARAMS_TITLE = "AudioRecordingDisclosureBar";
+    private static final int ANIM_DURATION_MS = 150;
+
+    private final Context mContext;
+    private final List<String> mAudioRecordingApps = new ArrayList<>();
+    private View mView;
+    private ViewGroup mAppsInfoContainer;
+
+    AudioRecordingDisclosureBar(Context context) {
+        mContext = context;
+    }
+
+    void start() {
+        // Inflate and add audio recording disclosure bar
+        createView();
+
+        // Register AppOpsManager callback
+        final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(
+                Context.APP_OPS_SERVICE);
+        appOpsManager.startWatchingActive(
+                new String[]{AppOpsManager.OPSTR_RECORD_AUDIO}, mContext.getMainExecutor(),
+                new OnActiveRecordingListener());
+    }
+
+    private void createView() {
+        mView = View.inflate(mContext,
+                R.layout.tv_status_bar_audio_recording, null);
+        mAppsInfoContainer = mView.findViewById(R.id.container);
+
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+                MATCH_PARENT,
+                WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSLUCENT);
+        layoutParams.gravity = Gravity.BOTTOM;
+        layoutParams.setTitle(LAYOUT_PARAMS_TITLE);
+        layoutParams.packageName = mContext.getPackageName();
+
+        final WindowManager windowManager = (WindowManager) mContext.getSystemService(
+                Context.WINDOW_SERVICE);
+        windowManager.addView(mView, layoutParams);
+
+        // Set invisible first util it gains its actual size and we are able to hide it by moving
+        // off the screen
+        mView.setVisibility(View.INVISIBLE);
+        mView.getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        // Now that we get the height, we can move the bar off ("below") the screen
+                        final int height = mView.getHeight();
+                        mView.setTranslationY(height);
+                        // ... and make it visible
+                        mView.setVisibility(View.VISIBLE);
+                        // Remove the observer
+                        mView.getViewTreeObserver()
+                                .removeOnGlobalLayoutListener(this);
+                    }
+                });
+    }
+
+    private void showAudioRecordingDisclosureBar() {
+        mView.animate()
+                .translationY(0f)
+                .setDuration(ANIM_DURATION_MS)
+                .start();
+    }
+
+    private void addToAudioRecordingDisclosureBar(String packageName) {
+        final PackageManager pm = mContext.getPackageManager();
+        final ApplicationInfo appInfo;
+        try {
+            appInfo = pm.getApplicationInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return;
+        }
+        final CharSequence label = pm.getApplicationLabel(appInfo);
+        final Drawable icon = pm.getApplicationIcon(appInfo);
+
+        final View view = LayoutInflater.from(mContext).inflate(R.layout.tv_item_app_info,
+                mAppsInfoContainer, false);
+        ((TextView) view.findViewById(R.id.title)).setText(label);
+        ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(icon);
+
+        mAppsInfoContainer.addView(view);
+    }
+
+    private void removeFromAudioRecordingDisclosureBar(int index) {
+        mAppsInfoContainer.removeViewAt(index);
+    }
+
+    private void hideAudioRecordingDisclosureBar() {
+        mView.animate()
+                .translationY(mView.getHeight())
+                .setDuration(ANIM_DURATION_MS)
+                .start();
+    }
+
+    private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener {
+        private final List<String> mExemptApps;
+
+        private OnActiveRecordingListener() {
+            mExemptApps = Arrays.asList(mContext.getResources().getStringArray(
+                    R.array.audio_recording_disclosure_exempt_apps));
+        }
+
+        @Override
+        public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
+            if (DEBUG) {
+                Log.d(TAG,
+                        "OP_RECORD_AUDIO active change, active" + active + ", app=" + packageName);
+            }
+
+            if (mExemptApps.contains(packageName)) {
+                if (DEBUG) {
+                    Log.d(TAG, "\t- exempt app");
+                }
+                return;
+            }
+
+            final boolean alreadyTracking = mAudioRecordingApps.contains(packageName);
+            if ((active && alreadyTracking) || (!active && !alreadyTracking)) {
+                if (DEBUG) {
+                    Log.d(TAG, "\t- nothing changed");
+                }
+                return;
+            }
+
+            if (active) {
+                if (DEBUG) {
+                    Log.d(TAG, "\t- new recording app");
+                }
+
+                if (mAudioRecordingApps.isEmpty()) {
+                    showAudioRecordingDisclosureBar();
+                }
+
+                mAudioRecordingApps.add(packageName);
+                addToAudioRecordingDisclosureBar(packageName);
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "\t- not recording any more");
+                }
+
+                final int index = mAudioRecordingApps.indexOf(packageName);
+                removeFromAudioRecordingDisclosureBar(index);
+                mAudioRecordingApps.remove(index);
+
+                if (mAudioRecordingApps.isEmpty()) {
+                    hideAudioRecordingDisclosureBar();
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 17d9cbe..b80b6d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -23,28 +23,33 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.CommandQueue.Callbacks;
+
 
 /**
- * Status bar implementation for "large screen" products that mostly present no on-screen nav
+ * Status bar implementation for "large screen" products that mostly present no on-screen nav.
+ * Serves as a collection of UI components, rather than showing its own UI.
+ * The following is the list of elements that constitute the TV-specific status bar:
+ * <ul>
+ * <li> {@link AudioRecordingDisclosureBar} - shown whenever applications are conducting audio
+ * recording, discloses the responsible applications </li>
+ * </ul>
  */
-
-public class TvStatusBar extends SystemUI implements Callbacks {
-
-    private IStatusBarService mBarService;
+public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
 
     @Override
     public void start() {
         putComponent(TvStatusBar.class, this);
-        CommandQueue commandQueue = getComponent(CommandQueue.class);
-        commandQueue.addCallback(this);
-        mBarService = IStatusBarService.Stub.asInterface(
+
+        final IStatusBarService barService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+        final CommandQueue commandQueue = getComponent(CommandQueue.class);
+        commandQueue.addCallback(this);
         try {
-            mBarService.registerStatusBar(commandQueue);
+            barService.registerStatusBar(commandQueue);
         } catch (RemoteException ex) {
             // If the system process isn't there we're doomed anyway.
         }
-    }
 
+        new AudioRecordingDisclosureBar(mContext).start();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index 583f6b3..db43906 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -49,7 +49,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIFactory;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -387,13 +387,15 @@
         public static final boolean ADD_TO_DEFAULT_ON_DEBUGGABLE_BUILDS = true;
 
         private final GarbageMonitor gm;
+        private final ActivityStarter mActivityStarter;
         private ProcessMemInfo pmi;
         private boolean dumpInProgress;
 
         @Inject
-        public MemoryTile(QSHost host) {
+        public MemoryTile(QSHost host, GarbageMonitor monitor, ActivityStarter starter) {
             super(host);
-            gm = SystemUIFactory.getInstance().getRootComponent().createGarbageMonitor();
+            gm = monitor;
+            mActivityStarter = starter;
         }
 
         @Override
@@ -424,7 +426,7 @@
                         dumpInProgress = false;
                         refreshState();
                         getHost().collapsePanels();
-                        mContext.startActivity(shareIntent);
+                        mActivityStarter.postStartActivityDismissingKeyguard(shareIntent, 0);
                     });
                 }
             }.start();
@@ -535,7 +537,12 @@
 
     /** */
     public static class Service extends SystemUI implements Dumpable {
-        private GarbageMonitor mGarbageMonitor;
+        private final GarbageMonitor mGarbageMonitor;
+
+        @Inject
+        public Service(GarbageMonitor garbageMonitor) {
+            mGarbageMonitor = garbageMonitor;
+        }
 
         @Override
         public void start() {
@@ -543,8 +550,6 @@
                     Settings.Secure.getInt(
                                     mContext.getContentResolver(), FORCE_ENABLE_LEAK_REPORTING, 0)
                             != 0;
-            mGarbageMonitor = SystemUIFactory.getInstance().getRootComponent()
-                   .createGarbageMonitor();
             if (LEAK_REPORTING_ENABLED || forceEnable) {
                 mGarbageMonitor.startLeakMonitor();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index edea92f..2c70fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -621,7 +621,9 @@
                 .PRIORITY_CATEGORY_MEDIA) == 0;
         boolean disallowSystem = (policy.priorityCategories & NotificationManager.Policy
                 .PRIORITY_CATEGORY_SYSTEM) == 0;
-        boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(policy);
+        // ringer controls notifications, ringer and system sounds, so only disallow ringer changes
+        // if all relevant (notifications + ringer + system) sounds are not allowed to bypass DND
+        boolean disallowRinger = ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(policy);
         if (mState.disallowAlarms == disallowAlarms
                 && mState.disallowMedia == disallowMedia
                 && mState.disallowRinger == disallowRinger
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 2e94c7c..ede717b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -125,7 +125,7 @@
 
         mCarrierTextCallbackInfo = new CarrierTextController.CarrierTextCallbackInfo("",
                 new CharSequence[]{}, false, new int[]{});
-        when(mTelephonyManager.getPhoneCount()).thenReturn(3);
+        when(mTelephonyManager.getMaxPhoneCount()).thenReturn(3);
 
         mCarrierTextController = new TestCarrierTextController(mContext, SEPARATOR, true, true,
                 mKeyguardUpdateMonitor);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 448c80e..2798c6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -74,6 +74,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -174,7 +175,8 @@
         TestableNotificationInterruptionStateProvider interruptionStateProvider =
                 new TestableNotificationInterruptionStateProvider(mContext,
                         mock(NotificationFilter.class),
-                        mock(StatusBarStateController.class));
+                        mock(StatusBarStateController.class),
+                        mock(BatteryController.class));
         interruptionStateProvider.setUpWithPresenter(
                 mock(NotificationPresenter.class),
                 mock(HeadsUpManager.class),
@@ -660,8 +662,9 @@
             NotificationInterruptionStateProvider {
 
         TestableNotificationInterruptionStateProvider(Context context,
-                NotificationFilter filter, StatusBarStateController controller) {
-            super(context, filter, controller);
+                NotificationFilter filter, StatusBarStateController controller,
+                BatteryController batteryController) {
+            super(context, filter, controller, batteryController);
             mUseHeadsUp = true;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index af2de1b..1ce0172 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -43,7 +43,6 @@
 import com.android.systemui.doze.DozeMachine.State;
 
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,12 +57,6 @@
     private Instrumentation mInstrumentation;
     private DockManagerFake mDockManagerFake;
 
-    @BeforeClass
-    public static void setupSuite() {
-        // We can't use KeyguardUpdateMonitor from tests.
-        DozeLog.setRegisterKeyguardCallback(false);
-    }
-
     @Before
     public void setUp() throws Exception {
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
@@ -95,7 +88,7 @@
 
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
 
-        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
     }
 
     @Test
@@ -105,14 +98,14 @@
 
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
 
-        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
     }
 
     @Test
     public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         when(mMachine.getState()).thenReturn(State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
 
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
 
@@ -123,7 +116,7 @@
     public void testOnEvent_undockedWhenPulsing_requestPulseOut() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
 
         mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
 
@@ -161,7 +154,7 @@
 
         TestableLooper.get(this).processAllMessages();
 
-        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
     }
 
     @Test
@@ -174,7 +167,7 @@
 
         TestableLooper.get(this).processAllMessages();
 
-        verify(mMachine).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
     }
 
     @Test
@@ -186,7 +179,7 @@
 
         mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
 
-        verify(mMachine, never()).requestPulse(eq(DozeLog.PULSE_REASON_DOCKING));
+        verify(mMachine, never()).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
     }
 
     @Test
@@ -205,7 +198,7 @@
     public void testTransitionToPulsing_whenDockedHide_requestPulseOut() {
         mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_DOCKING);
+        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
 
         mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_PULSING);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index 1e18e51..bbd2ab1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -46,6 +46,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.wakelock.WakeLockFake;
 
 import org.junit.Before;
@@ -63,6 +64,8 @@
 
     @Mock
     private WakefulnessLifecycle mWakefulnessLifecycle;
+    @Mock
+    private DozeLog mDozeLog;
     private DozeServiceFake mServiceFake;
     private WakeLockFake mWakeLockFake;
     private AmbientDisplayConfiguration mConfigMock;
@@ -76,8 +79,8 @@
         mConfigMock = mock(AmbientDisplayConfiguration.class);
         mPartMock = mock(DozeMachine.Part.class);
 
-        mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake, mWakefulnessLifecycle);
-
+        mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
+                mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog);
         mMachine.setParts(new DozeMachine.Part[]{mPartMock});
     }
 
@@ -112,7 +115,7 @@
     public void testPulseDone_goesToDoze() {
         when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
         mMachine.requestState(INITIALIZED);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
 
         mMachine.requestState(DOZE_PULSE_DONE);
@@ -125,7 +128,7 @@
     public void testPulseDone_goesToAoD() {
         when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
         mMachine.requestState(INITIALIZED);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
 
         mMachine.requestState(DOZE_PULSE_DONE);
@@ -169,7 +172,7 @@
     public void testWakeLock_heldInPulseStates() {
         mMachine.requestState(INITIALIZED);
 
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         assertTrue(mWakeLockFake.isHeld());
 
         mMachine.requestState(DOZE_PULSING);
@@ -192,7 +195,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
         mMachine.requestState(DOZE_PULSE_DONE);
 
@@ -204,9 +207,9 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSE_DONE);
     }
 
@@ -215,7 +218,7 @@
         mMachine.requestState(INITIALIZED);
 
         mMachine.requestState(DOZE);
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSE_DONE);
     }
 
@@ -228,7 +231,7 @@
             return null;
         }).when(mPartMock).transitionTo(any(), eq(DOZE_REQUEST_PULSE));
 
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
 
         assertEquals(DOZE_PULSING, mMachine.getState());
     }
@@ -237,9 +240,9 @@
     public void testPulseReason_getMatchesRequest() {
         mMachine.requestState(INITIALIZED);
         mMachine.requestState(DOZE);
-        mMachine.requestPulse(DozeLog.REASON_SENSOR_DOUBLE_TAP);
+        mMachine.requestPulse(DozeEvent.REASON_SENSOR_DOUBLE_TAP);
 
-        assertEquals(DozeLog.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason());
+        assertEquals(DozeEvent.REASON_SENSOR_DOUBLE_TAP, mMachine.getPulseReason());
     }
 
     @Test
@@ -251,7 +254,7 @@
             if (newState == DOZE_REQUEST_PULSE
                     || newState == DOZE_PULSING
                     || newState == DOZE_PULSE_DONE) {
-                assertEquals(DozeLog.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason());
+                assertEquals(DozeEvent.PULSE_REASON_NOTIFICATION, mMachine.getPulseReason());
             } else {
                 assertTrue("unexpected state " + newState,
                         newState == DOZE || newState == DOZE_AOD);
@@ -259,7 +262,7 @@
             return null;
         }).when(mPartMock).transitionTo(any(), any());
 
-        mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
         mMachine.requestState(DOZE_PULSING);
         mMachine.requestState(DOZE_PULSE_DONE);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index ddd1685..f2665ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -78,6 +78,8 @@
     private AlwaysOnDisplayPolicy mAlwaysOnDisplayPolicy;
     @Mock
     private TriggerSensor mTriggerSensor;
+    @Mock
+    private DozeLog mDozeLog;
     private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
     private TestableLooper mTestableLooper;
     private DozeSensors mDozeSensors;
@@ -101,14 +103,14 @@
 
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
-        verify(mCallback).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+        verify(mCallback).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
                 anyFloat(), anyFloat(), eq(null));
 
         mDozeSensors.requestTemporaryDisable();
         reset(mCallback);
         mWakeLockScreenListener.onSensorChanged(mock(SensorManagerPlugin.SensorEvent.class));
         mTestableLooper.processAllMessages();
-        verify(mCallback, never()).onSensorPulse(eq(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
+        verify(mCallback, never()).onSensorPulse(eq(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN),
                 anyFloat(), anyFloat(), eq(null));
     }
 
@@ -146,7 +148,7 @@
         TestableDozeSensors() {
             super(getContext(), mAlarmManager, mSensorManager, mDozeParameters,
                     mAmbientDisplayConfiguration, mWakeLock, mCallback, mProxCallback,
-                    mAlwaysOnDisplayPolicy);
+                    mAlwaysOnDisplayPolicy, mDozeLog);
             for (TriggerSensor sensor : mSensors) {
                 if (sensor instanceof PluginSensor
                         && ((PluginSensor) sensor).mPluginSensor.getType()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index b0e3969..e5ae6d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -48,7 +48,6 @@
 import com.android.systemui.util.wakelock.WakeLockFake;
 
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -64,12 +63,6 @@
     private DockManager mDockManagerFake;
     private FakeProximitySensor mProximitySensor;
 
-    @BeforeClass
-    public static void setupSuite() {
-        // We can't use KeyguardUpdateMonitor from tests.
-        DozeLog.setRegisterKeyguardCallback(false);
-    }
-
     @Before
     public void setUp() throws Exception {
         mMachine = mock(DozeMachine.class);
@@ -87,7 +80,7 @@
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, alarmManager, config, parameters,
                 asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
-                mDockManagerFake, mProximitySensor);
+                mDockManagerFake, mProximitySensor, mock(DozeLog.class));
         waitForSensorManager();
     }
 
@@ -148,9 +141,10 @@
     @Test
     public void testProximitySensorNotAvailablel() {
         mProximitySensor.setSensorAvailable(false);
-        mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null);
-        mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100, new float[]{1});
-        mTriggers.onSensor(DozeLog.REASON_SENSOR_TAP, 100, 100, null);
+        mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null);
+        mTriggers.onSensor(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN, 100, 100,
+                new float[]{1});
+        mTriggers.onSensor(DozeEvent.REASON_SENSOR_TAP, 100, 100, null);
     }
 
     private void waitForSensorManager() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
index 25231bc..c5bddc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeUiTest.java
@@ -65,6 +65,8 @@
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
     private DozeHost mHost;
+    @Mock
+    private DozeLog mDozeLog;
     private WakeLockFake mWakeLock;
     private Handler mHandler;
     private HandlerThread mHandlerThread;
@@ -80,7 +82,7 @@
         mHandler = mHandlerThread.getThreadHandler();
 
         mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
-                mDozeParameters, mKeyguardUpdateMonitor);
+                mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
     }
 
     @After
@@ -135,7 +137,7 @@
         reset(mHost);
         when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
         mDozeUi = new DozeUi(mContext, mAlarmManager, mMachine, mWakeLock, mHost, mHandler,
-                mDozeParameters, mKeyguardUpdateMonitor);
+                mDozeParameters, mKeyguardUpdateMonitor, mDozeLog);
 
         // Never animate if display doesn't support it.
         mDozeUi.getKeyguardCallback().onKeyguardVisibilityChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
new file mode 100644
index 0000000..2f90641
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/RichEventTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.log;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class RichEventTest extends SysuiTestCase {
+
+    private static final int TOTAL_EVENT_TYPES = 1;
+
+    @Test
+    public void testCreateRichEvent_invalidType() {
+        try {
+            // indexing for events starts at 0, so TOTAL_EVENT_TYPES is an invalid type
+            new TestableRichEvent(Event.DEBUG, TOTAL_EVENT_TYPES, "msg");
+        } catch (IllegalArgumentException e) {
+            // expected
+            return;
+        }
+
+        Assert.fail("Expected an invalidArgumentException since the event type was invalid.");
+    }
+
+    @Test
+    public void testCreateRichEvent() {
+        final int eventType = 0;
+        RichEvent e = new TestableRichEvent(Event.DEBUG, eventType, "msg");
+        assertEquals(e.getType(), eventType);
+    }
+
+    class TestableRichEvent extends RichEvent {
+        TestableRichEvent(int logLevel, int type, String reason) {
+            super(logLevel, type, reason);
+        }
+
+        @Override
+        public String[] getEventLabels() {
+            return new String[]{"ACTION_NAME"};
+        }
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
new file mode 100644
index 0000000..378bba1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/SysuiLogTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.log;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.DumpController;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class SysuiLogTest extends SysuiTestCase {
+    private static final String TEST_ID = "TestLogger";
+    private static final int MAX_LOGS = 5;
+
+    @Mock
+    private DumpController mDumpController;
+    private SysuiLog mSysuiLog;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testLogDisabled_noLogsWritten() {
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, false);
+        assertEquals(mSysuiLog.mTimeline, null);
+
+        mSysuiLog.log(new Event("msg"));
+        assertEquals(mSysuiLog.mTimeline, null);
+    }
+
+    @Test
+    public void testLogEnabled_logWritten() {
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+        assertEquals(mSysuiLog.mTimeline.size(), 0);
+
+        mSysuiLog.log(new Event("msg"));
+        assertEquals(mSysuiLog.mTimeline.size(), 1);
+    }
+
+    @Test
+    public void testMaxLogs() {
+        mSysuiLog = new SysuiLog(mDumpController, TEST_ID, MAX_LOGS, true);
+        assertEquals(mSysuiLog.mTimeline.size(), 0);
+
+        final String msg = "msg";
+        for (int i = 0; i < MAX_LOGS + 1; i++) {
+            mSysuiLog.log(new Event(msg + i));
+        }
+
+        assertEquals(mSysuiLog.mTimeline.size(), MAX_LOGS);
+
+        // check the first message (msg0) is deleted:
+        assertEquals(mSysuiLog.mTimeline.getFirst().getMessage(), msg + "1");
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
index 7d2ccdc..618272c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -240,4 +241,10 @@
 
         verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
     }
+
+    @Test
+    public void testGetAssistHandlerViewController_noCrash() {
+        reset(mNavigationBarController.mNavigationBars);
+        mNavigationBarController.getAssistHandlerViewController();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
index 350ab5a..28a7e40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
@@ -84,6 +85,8 @@
     HeadsUpManager mHeadsUpManager;
     @Mock
     NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
+    @Mock
+    BatteryController mBatteryController;
 
     private NotificationInterruptionStateProvider mNotifInterruptionStateProvider;
 
@@ -97,7 +100,8 @@
                         mDreamManager,
                         mAmbientDisplayConfiguration,
                         mNotificationFilter,
-                        mStatusBarStateController);
+                        mStatusBarStateController,
+                        mBatteryController);
 
         mNotifInterruptionStateProvider.setUpWithPresenter(
                 mPresenter,
@@ -590,17 +594,17 @@
     /**
      * Testable class overriding constructor.
      */
-    public class TestableNotificationInterruptionStateProvider extends
+    public static class TestableNotificationInterruptionStateProvider extends
             NotificationInterruptionStateProvider {
 
         TestableNotificationInterruptionStateProvider(Context context,
                 PowerManager powerManager, IDreamManager dreamManager,
                 AmbientDisplayConfiguration ambientDisplayConfiguration,
                 NotificationFilter notificationFilter,
-                StatusBarStateController statusBarStateController) {
+                StatusBarStateController statusBarStateController,
+                BatteryController batteryController) {
             super(context, powerManager, dreamManager, ambientDisplayConfiguration,
-                    notificationFilter,
-                    statusBarStateController);
+                    notificationFilter, batteryController, statusBarStateController);
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
index 20c739f..1ce336e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeScrimControllerTest.java
@@ -27,6 +27,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.doze.DozeHost;
+import com.android.systemui.doze.DozeLog;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -41,12 +42,14 @@
 
     @Mock
     private DozeParameters mDozeParameters;
+    @Mock
+    private DozeLog mDozeLog;
     private DozeScrimController mDozeScrimController;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mDozeScrimController = new DozeScrimController(mDozeParameters);
+        mDozeScrimController = new DozeScrimController(mDozeParameters, mDozeLog);
         mDozeScrimController.setDozing(true);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 219aef1..f1da4e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -40,6 +40,8 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.plugins.PluginManager;
@@ -129,9 +131,13 @@
                         mock(HeadsUpManagerPhone.class),
                         new StatusBarStateControllerImpl(),
                         mKeyguardBypassController);
-        PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator,
+        PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
+                mContext,
+                coordinator,
                 mKeyguardBypassController, mHeadsUpManager,
-                mock(NotificationRoundnessManager.class), mStatusBarStateController);
+                mock(NotificationRoundnessManager.class),
+                mStatusBarStateController,
+                new FalsingManagerFake());
         mNotificationPanelView = new TestableNotificationPanelView(coordinator, expansionHandler,
                 mKeyguardBypassController);
         mNotificationPanelView.setHeadsUpManager(mHeadsUpManager);
@@ -216,7 +222,7 @@
                             SystemUIFactory.getInstance().getRootComponent()),
                     coordinator, expansionHandler, mock(DynamicPrivacyController.class),
                     bypassController,
-                    mFalsingManager, mock(PluginManager.class));
+                    mFalsingManager, mock(PluginManager.class), mock(DozeLog.class));
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index f1aaf3d..214e26a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -46,6 +46,7 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.util.function.TriConsumer;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -95,6 +96,7 @@
         mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
         when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
         when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
+        DejankUtils.setImmediate(true);
         mScrimController = new SynchronousScrimController(mScrimBehind, mScrimInFront,
                 mScrimForBubble,
                 (scrimState, scrimBehindAlpha, scrimInFrontColor) -> {
@@ -113,6 +115,7 @@
     @After
     public void tearDown() {
         mScrimController.finishAnimationsImmediately();
+        DejankUtils.setImmediate(false);
     }
 
     @Test
@@ -433,6 +436,7 @@
                 TRANSPARENT /* behind */,
                 TRANSPARENT /* bubble */);
 
+        // Make sure at the very end of the animation, we're reset to transparent
         assertScrimTint(false /* front */,
                 false /* behind */,
                 false  /* bubble */);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index c3b25ce..aafcdd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -227,6 +227,31 @@
         verify(mStatusBar, never()).animateKeyguardUnoccluding();
     }
 
+    @Test
+    public void testHiding_cancelsGoneRunnable() {
+        OnDismissAction action = mock(OnDismissAction.class);
+        Runnable cancelAction = mock(Runnable.class);
+        mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
+                true /* afterKeyguardGone */);
+
+        mStatusBarKeyguardViewManager.hideBouncer(true);
+        mStatusBarKeyguardViewManager.hide(0, 30);
+        verify(action, never()).onDismiss();
+        verify(cancelAction).run();
+    }
+
+    @Test
+    public void testHiding_doesntCancelWhenShowing() {
+        OnDismissAction action = mock(OnDismissAction.class);
+        Runnable cancelAction = mock(Runnable.class);
+        mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction,
+                true /* afterKeyguardGone */);
+
+        mStatusBarKeyguardViewManager.hide(0, 30);
+        verify(action).onDismiss();
+        verify(cancelAction, never()).run();
+    }
+
     private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
 
         public TestableStatusBarKeyguardViewManager(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index b75cb8c..7de7f9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -80,8 +80,8 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.doze.DozeEvent;
 import com.android.systemui.doze.DozeHost;
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
@@ -113,6 +113,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
+import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -132,7 +133,7 @@
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
 public class StatusBarTest extends SysuiTestCase {
     @Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     @Mock private KeyguardStateController mKeyguardStateController;
@@ -159,6 +160,7 @@
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
+    @Mock private BatteryController mBatteryController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarNotificationPresenter mNotificationPresenter;
     @Mock
@@ -214,7 +216,7 @@
         mNotificationInterruptionStateProvider =
                 new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
                         mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
-                        mStatusBarStateController);
+                        mStatusBarStateController, mBatteryController);
         mDependency.injectTestDependency(NotificationInterruptionStateProvider.class,
                 mNotificationInterruptionStateProvider);
         mDependency.injectMockDependency(NavigationBarController.class);
@@ -230,7 +232,6 @@
                 mExpansionStateLogger);
         mNotificationLogger.setVisibilityReporter(mock(Runnable.class));
         mDependency.injectTestDependency(NotificationLogger.class, mNotificationLogger);
-        DozeLog.traceDozing(mContext, false /* dozing */);
 
         mCommandQueue = mock(CommandQueue.class);
         when(mCommandQueue.asBinder()).thenReturn(new Binder());
@@ -652,7 +653,7 @@
 
         // Starting a pulse should change the scrim controller to the pulsing state
         mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
-                DozeLog.PULSE_REASON_NOTIFICATION);
+                DozeEvent.PULSE_REASON_NOTIFICATION);
         verify(mScrimController).transitionTo(eq(ScrimState.PULSING), any());
 
         // Ending a pulse should take it back to keyguard state
@@ -663,21 +664,21 @@
     @Test
     public void testPulseWhileDozing_notifyAuthInterrupt() {
         HashSet<Integer> reasonsWantingAuth = new HashSet<>(
-                Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
+                Collections.singletonList(DozeEvent.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
         HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
-                Arrays.asList(DozeLog.PULSE_REASON_INTENT,
-                        DozeLog.PULSE_REASON_NOTIFICATION,
-                        DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
-                        DozeLog.REASON_SENSOR_PICKUP,
-                        DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                        DozeLog.PULSE_REASON_SENSOR_LONG_PRESS,
-                        DozeLog.PULSE_REASON_DOCKING,
-                        DozeLog.REASON_SENSOR_WAKE_UP,
-                        DozeLog.REASON_SENSOR_TAP));
+                Arrays.asList(DozeEvent.PULSE_REASON_INTENT,
+                        DozeEvent.PULSE_REASON_NOTIFICATION,
+                        DozeEvent.PULSE_REASON_SENSOR_SIGMOTION,
+                        DozeEvent.REASON_SENSOR_PICKUP,
+                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
+                        DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS,
+                        DozeEvent.PULSE_REASON_DOCKING,
+                        DozeEvent.REASON_SENSOR_WAKE_UP,
+                        DozeEvent.REASON_SENSOR_TAP));
         HashSet<Integer> reasonsThatDontPulse = new HashSet<>(
-                Arrays.asList(DozeLog.REASON_SENSOR_PICKUP,
-                        DozeLog.REASON_SENSOR_DOUBLE_TAP,
-                        DozeLog.REASON_SENSOR_TAP));
+                Arrays.asList(DozeEvent.REASON_SENSOR_PICKUP,
+                        DozeEvent.REASON_SENSOR_DOUBLE_TAP,
+                        DozeEvent.REASON_SENSOR_TAP));
 
         doAnswer(invocation -> {
             DozeHost.PulseCallback callback = invocation.getArgument(0);
@@ -686,7 +687,7 @@
         }).when(mDozeScrimController).pulse(any(), anyInt());
 
         mStatusBar.mDozeServiceHost.mWakeLockScreenPerformsAuth = true;
-        for (int i = 0; i < DozeLog.REASONS; i++) {
+        for (int i = 0; i < DozeEvent.TOTAL_REASONS; i++) {
             reset(mKeyguardUpdateMonitor);
             mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class), i);
             if (reasonsWantingAuth.contains(i)) {
@@ -711,7 +712,7 @@
 
         // Starting a pulse while docking should suppress wakeup gesture
         mStatusBar.mDozeServiceHost.pulseWhileDozing(mock(DozeHost.PulseCallback.class),
-                DozeLog.PULSE_REASON_DOCKING);
+                DozeEvent.PULSE_REASON_DOCKING);
         verify(mStatusBarWindowView).suppressWakeUpGesture(eq(true));
 
         // Ending a pulse should restore wakeup gesture
@@ -907,9 +908,10 @@
                 IDreamManager dreamManager,
                 AmbientDisplayConfiguration ambientDisplayConfiguration,
                 NotificationFilter filter,
-                StatusBarStateController controller) {
+                StatusBarStateController controller,
+                BatteryController batteryController) {
             super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter,
-                    controller);
+                    batteryController, controller);
             mUseHeadsUp = true;
         }
     }
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 a843cca..df76f01 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
@@ -48,4 +48,9 @@
     public boolean isPowerSave() {
         return false;
     }
+
+    @Override
+    public boolean isAodPowerSave() {
+        return false;
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index dc7a9aa..5ac3b69 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -72,10 +72,16 @@
      *
      * @param prototype The prototype from which to create the injected events.
      * @param action The action of the event.
+     * @param rawEvent The original event prior to magnification or other transformations.
      * @param pointerIdBits The bits of the pointers to send.
      * @param policyFlags The policy flags associated with the event.
      */
-    void sendMotionEvent(MotionEvent prototype, int action, int pointerIdBits, int policyFlags) {
+    void sendMotionEvent(
+            MotionEvent prototype,
+            int action,
+            MotionEvent rawEvent,
+            int pointerIdBits,
+            int policyFlags) {
         prototype.setAction(action);
 
         MotionEvent event = null;
@@ -105,11 +111,8 @@
 
         // Make sure that the user will see the event.
         policyFlags |= WindowManagerPolicy.FLAG_PASS_TO_USER;
-        // TODO: For now pass null for the raw event since the touch
-        //       explorer is the last event transformation and it does
-        //       not care about the raw event.
         if (mReceiver != null) {
-            mReceiver.onMotionEvent(event, null, policyFlags);
+            mReceiver.onMotionEvent(event, rawEvent, policyFlags);
         } else {
             Slog.e(LOG_TAG, "Error sending event: no receiver specified.");
         }
@@ -280,7 +283,12 @@
             if (!isInjectedPointerDown(pointerId)) {
                 pointerIdBits |= (1 << pointerId);
                 final int action = computeInjectionAction(MotionEvent.ACTION_DOWN, i);
-                sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
+                sendMotionEvent(
+                        prototype,
+                        action,
+                        mState.getLastReceivedEvent(),
+                        pointerIdBits,
+                        policyFlags);
             }
         }
     }
@@ -303,7 +311,8 @@
             }
             pointerIdBits |= (1 << pointerId);
             final int action = computeInjectionAction(MotionEvent.ACTION_UP, i);
-            sendMotionEvent(prototype, action, pointerIdBits, policyFlags);
+            sendMotionEvent(
+                    prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags);
         }
     }
 }
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 f4ac821..c60e35e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -183,9 +183,9 @@
     private void clear() {
         // If we have not received an event then we are in initial
         // state. Therefore, there is not need to clean anything.
-        MotionEvent event = mReceivedPointerTracker.getLastReceivedEvent();
+        MotionEvent event = mState.getLastReceivedEvent();
         if (event != null) {
-            clear(mReceivedPointerTracker.getLastReceivedEvent(), WindowManagerPolicy.FLAG_TRUSTED);
+            clear(event, WindowManagerPolicy.FLAG_TRUSTED);
         }
     }
 
@@ -229,7 +229,7 @@
             Slog.d(LOG_TAG, mState.toString());
         }
 
-        mReceivedPointerTracker.onMotionEvent(rawEvent);
+        mState.onReceivedMotionEvent(rawEvent);
 
         if (mGestureDetector.onMotionEvent(event, rawEvent, policyFlags)) {
             // Event was handled by the gesture detector.
@@ -250,9 +250,9 @@
         } else if (mState.isTouchExploring()) {
             handleMotionEventStateTouchExploring(event, rawEvent, policyFlags);
         } else if (mState.isDragging()) {
-            handleMotionEventStateDragging(event, policyFlags);
+            handleMotionEventStateDragging(event, rawEvent, policyFlags);
         } else if (mState.isDelegating()) {
-            handleMotionEventStateDelegating(event, policyFlags);
+            handleMotionEventStateDelegating(event, rawEvent, policyFlags);
         } else if (mState.isGestureDetecting()) {
             // Already handled.
         } else {
@@ -292,7 +292,7 @@
         }
 
         // Pointers should not be zero when running this command.
-        if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
+        if (mState.getLastReceivedEvent().getPointerCount() == 0) {
             return;
         }
         // Try to use the standard accessibility API to long click
@@ -368,11 +368,15 @@
 
                 // We have just decided that the user is touch,
                 // exploring so start sending events.
-                mSendHoverEnterAndMoveDelayed.addEvent(event);
+                mSendHoverEnterAndMoveDelayed.addEvent(event, mState.getLastReceivedEvent());
                 mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
                 mSendHoverExitDelayed.cancel();
                 mDispatcher.sendMotionEvent(
-                        event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+                        event,
+                        MotionEvent.ACTION_HOVER_MOVE,
+                        mState.getLastReceivedEvent(),
+                        pointerIdBits,
+                        policyFlags);
                 return true;
             }
         }
@@ -387,7 +391,7 @@
         switch (event.getActionMasked()) {
             // The only way to leave the clear state is for a pointer to go down.
             case MotionEvent.ACTION_DOWN:
-                handleActionDown(event, policyFlags);
+                handleActionDown(event, rawEvent, policyFlags);
                 break;
             default:
                 // Some other nonsensical event.
@@ -399,7 +403,7 @@
      * Handles ACTION_DOWN while in the clear or touch interacting states. This event represents the
      * first finger touching the screen.
      */
-    private void handleActionDown(MotionEvent event, int policyFlags) {
+    private void handleActionDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         mAms.onTouchInteractionStart();
 
         // If we still have not notified the user for the last
@@ -432,10 +436,10 @@
                 // The idea is to avoid getting stuck in STATE_TOUCH_INTERACTING
                 final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
                 final int pointerIdBits = (1 << pointerId);
-                mSendHoverEnterAndMoveDelayed.post(event, pointerIdBits, policyFlags);
+                mSendHoverEnterAndMoveDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
             } else {
                 // Cache the event until we discern exploration from gesturing.
-                mSendHoverEnterAndMoveDelayed.addEvent(event);
+                mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
             }
         }
     }
@@ -453,7 +457,7 @@
             case MotionEvent.ACTION_DOWN:
                 // Continue the previous interaction.
                 mSendTouchInteractionEndDelayed.cancel();
-                handleActionDown(event, policyFlags);
+                handleActionDown(event, rawEvent, policyFlags);
                 break;
             case MotionEvent.ACTION_POINTER_DOWN:
                 handleActionPointerDown();
@@ -462,7 +466,7 @@
                 handleActionMoveStateTouchInteracting(event, rawEvent, policyFlags);
                 break;
             case MotionEvent.ACTION_UP:
-                handleActionUp(event, policyFlags);
+                handleActionUp(event, rawEvent, policyFlags);
                 break;
         }
     }
@@ -487,7 +491,7 @@
                 handleActionMoveStateTouchExploring(event, rawEvent, policyFlags);
                 break;
             case MotionEvent.ACTION_UP:
-                handleActionUp(event, policyFlags);
+                handleActionUp(event, rawEvent, policyFlags);
                 break;
             default:
                 break;
@@ -520,7 +524,7 @@
                 // figure out what the user is doing.
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
                     // Cache the event until we discern exploration from gesturing.
-                    mSendHoverEnterAndMoveDelayed.addEvent(event);
+                    mSendHoverEnterAndMoveDelayed.addEvent(event, rawEvent);
                 }
                 break;
             case 2:
@@ -538,7 +542,7 @@
                     mDraggingPointerId = pointerId;
                     event.setEdgeFlags(mReceivedPointerTracker.getLastReceivedDownEdgeFlags());
                     mDispatcher.sendMotionEvent(
-                            event, MotionEvent.ACTION_DOWN, pointerIdBits, policyFlags);
+                            event, MotionEvent.ACTION_DOWN, rawEvent, pointerIdBits, policyFlags);
                 } else {
                     // Two pointers moving arbitrary are delegated to the view hierarchy.
                     mState.startDelegating();
@@ -558,13 +562,13 @@
      * Handles ACTION_UP while in the touch interacting state. This event represents all fingers
      * being lifted from the screen.
      */
-    private void handleActionUp(MotionEvent event, int policyFlags) {
+    private void handleActionUp(MotionEvent event,  MotionEvent rawEvent, int policyFlags) {
         mAms.onTouchInteractionEnd();
         final int pointerId = event.getPointerId(event.getActionIndex());
         final int pointerIdBits = (1 << pointerId);
         if (mSendHoverEnterAndMoveDelayed.isPending()) {
             // If we have not delivered the enter schedule an exit.
-            mSendHoverExitDelayed.post(event, pointerIdBits, policyFlags);
+            mSendHoverExitDelayed.post(event, rawEvent, pointerIdBits, policyFlags);
         } else {
             // The user is touch exploring so we send events for end.
             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -588,7 +592,7 @@
             // Touch exploration.
                 sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                 mDispatcher.sendMotionEvent(
-                        event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+                        event, MotionEvent.ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
                 break;
             case 2:
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
@@ -638,7 +642,8 @@
      * @param event The event to be handled.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void handleMotionEventStateDragging(MotionEvent event, int policyFlags) {
+    private void handleMotionEventStateDragging(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         int pointerIdBits = 0;
         // Clear the dragging pointer id if it's no longer valid.
         if (event.findPointerIndex(mDraggingPointerId) == -1) {
@@ -662,7 +667,7 @@
                 mState.startDelegating();
                 if (mDraggingPointerId != INVALID_POINTER_ID) {
                     mDispatcher.sendMotionEvent(
-                            event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                            event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
                 }
                 mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
             } break;
@@ -681,6 +686,7 @@
                             mDispatcher.sendMotionEvent(
                                     event,
                                     MotionEvent.ACTION_MOVE,
+                                    rawEvent,
                                     pointerIdBits,
                                     policyFlags);
                         } else {
@@ -690,7 +696,11 @@
                             // Remove move history before send injected non-move events
                             event = MotionEvent.obtainNoHistory(event);
                             // Send an event to the end of the drag gesture.
-                            mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+                            mDispatcher.sendMotionEvent(
+                                    event,
+                                    MotionEvent.ACTION_UP,
+                                    rawEvent,
+                                    pointerIdBits,
                                     policyFlags);
                             // Deliver all pointers to the view hierarchy.
                             mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
@@ -700,7 +710,11 @@
                         mState.startDelegating();
                         event = MotionEvent.obtainNoHistory(event);
                         // Send an event to the end of the drag gesture.
-                        mDispatcher.sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits,
+                        mDispatcher.sendMotionEvent(
+                                event,
+                                MotionEvent.ACTION_UP,
+                                rawEvent,
+                                pointerIdBits,
                                 policyFlags);
                         // Deliver all pointers to the view hierarchy.
                         mDispatcher.sendDownForAllNotInjectedPointers(event, policyFlags);
@@ -713,7 +727,7 @@
                     mDraggingPointerId = INVALID_POINTER_ID;
                         // Send an event to the end of the drag gesture.
                     mDispatcher.sendMotionEvent(
-                            event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                            event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
                  }
             } break;
             case MotionEvent.ACTION_UP: {
@@ -726,7 +740,7 @@
                     mDraggingPointerId = INVALID_POINTER_ID;
                     // Send an event to the end of the drag gesture.
                     mDispatcher.sendMotionEvent(
-                            event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
+                            event, MotionEvent.ACTION_UP, rawEvent, pointerIdBits, policyFlags);
                 }
             } break;
         }
@@ -738,7 +752,8 @@
      * @param event The event to be handled.
      * @param policyFlags The policy flags associated with the event.
      */
-    private void handleMotionEventStateDelegating(MotionEvent event, int policyFlags) {
+    private void handleMotionEventStateDelegating(
+            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
         switch (event.getActionMasked()) {
             case MotionEvent.ACTION_DOWN: {
                 Slog.e(LOG_TAG, "Delegating state can only be reached if "
@@ -749,7 +764,7 @@
             case MotionEvent.ACTION_UP: {
                 // Deliver the event.
                 mDispatcher.sendMotionEvent(
-                        event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
+                        event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags);
 
                 // Announce the end of a the touch interaction.
                 mAms.onTouchInteractionEnd();
@@ -759,7 +774,7 @@
             default: {
                     // Deliver the event.
                 mDispatcher.sendMotionEvent(
-                        event, event.getAction(), ALL_POINTER_ID_BITS, policyFlags);
+                        event, event.getAction(), rawEvent, ALL_POINTER_ID_BITS, policyFlags);
             }
         }
     }
@@ -792,7 +807,11 @@
                 mSendTouchExplorationEndDelayed.post();
             }
             mDispatcher.sendMotionEvent(
-                    event, MotionEvent.ACTION_HOVER_EXIT, pointerIdBits, policyFlags);
+                    event,
+                    MotionEvent.ACTION_HOVER_EXIT,
+                    mState.getLastReceivedEvent(),
+                    pointerIdBits,
+                    policyFlags);
         }
     }
 
@@ -807,7 +826,11 @@
         if (event != null && event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT) {
             final int pointerIdBits = event.getPointerIdBits();
             mDispatcher.sendMotionEvent(
-                    event, MotionEvent.ACTION_HOVER_ENTER, pointerIdBits, policyFlags);
+                    event,
+                    MotionEvent.ACTION_HOVER_ENTER,
+                    mState.getLastReceivedEvent(),
+                    pointerIdBits,
+                    policyFlags);
         }
     }
 
@@ -891,20 +914,23 @@
         private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverEnterAndMoveDelayed";
 
         private final List<MotionEvent> mEvents = new ArrayList<MotionEvent>();
+        private final List<MotionEvent> mRawEvents = new ArrayList<MotionEvent>();
 
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public void post(MotionEvent event, int pointerIdBits, int policyFlags) {
+        public void post(
+                MotionEvent event, MotionEvent rawEvent, int pointerIdBits, int policyFlags) {
             cancel();
-            addEvent(event);
+            addEvent(event, rawEvent);
             mPointerIdBits = pointerIdBits;
             mPolicyFlags = policyFlags;
             mHandler.postDelayed(this, mDetermineUserIntentTimeout);
         }
 
-        public void addEvent(MotionEvent event) {
+        public void addEvent(MotionEvent event, MotionEvent rawEvent) {
             mEvents.add(MotionEvent.obtain(event));
+            mRawEvents.add(MotionEvent.obtain(rawEvent));
         }
 
         public void cancel() {
@@ -925,6 +951,10 @@
             for (int i = eventCount - 1; i >= 0; i--) {
                 mEvents.remove(i).recycle();
             }
+            final int rawEventcount = mRawEvents.size();
+            for (int i = rawEventcount - 1; i >= 0; i--) {
+                mRawEvents.remove(i).recycle();
+            }
         }
 
         public void forceSendAndRemove() {
@@ -939,10 +969,10 @@
             mDispatcher.sendAccessibilityEvent(
                     AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
 
-            if (!mEvents.isEmpty()) {
+            if (!mEvents.isEmpty() && !mRawEvents.isEmpty()) {
                 // Deliver a down event.
                 mDispatcher.sendMotionEvent(mEvents.get(0), MotionEvent.ACTION_HOVER_ENTER,
-                        mPointerIdBits, mPolicyFlags);
+                        mRawEvents.get(0), mPointerIdBits, mPolicyFlags);
                 if (DEBUG) {
                     Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
                             "Injecting motion event: ACTION_HOVER_ENTER");
@@ -952,7 +982,7 @@
                 final int eventCount = mEvents.size();
                 for (int i = 1; i < eventCount; i++) {
                     mDispatcher.sendMotionEvent(mEvents.get(i), MotionEvent.ACTION_HOVER_MOVE,
-                            mPointerIdBits, mPolicyFlags);
+                            mRawEvents.get(i), mPointerIdBits, mPolicyFlags);
                     if (DEBUG) {
                         Slog.d(LOG_TAG_SEND_HOVER_DELAYED,
                                 "Injecting motion event: ACTION_HOVER_MOVE");
@@ -970,12 +1000,15 @@
         private final String LOG_TAG_SEND_HOVER_DELAYED = "SendHoverExitDelayed";
 
         private MotionEvent mPrototype;
+        private MotionEvent mRawEvent;
         private int mPointerIdBits;
         private int mPolicyFlags;
 
-        public void post(MotionEvent prototype, int pointerIdBits, int policyFlags) {
+        public void post(
+                MotionEvent prototype, MotionEvent rawEvent, int pointerIdBits, int policyFlags) {
             cancel();
             mPrototype = MotionEvent.obtain(prototype);
+            mRawEvent = MotionEvent.obtain(rawEvent);
             mPointerIdBits = pointerIdBits;
             mPolicyFlags = policyFlags;
             mHandler.postDelayed(this, mDetermineUserIntentTimeout);
@@ -993,8 +1026,14 @@
         }
 
         private void clear() {
-            mPrototype.recycle();
+            if (mPrototype != null) {
+                mPrototype.recycle();
+            }
+            if (mRawEvent != null) {
+                mRawEvent.recycle();
+            }
             mPrototype = null;
+            mRawEvent = null;
             mPointerIdBits = -1;
             mPolicyFlags = 0;
         }
@@ -1011,8 +1050,12 @@
                 Slog.d(LOG_TAG_SEND_HOVER_DELAYED, "Injecting motion event:"
                         + " ACTION_HOVER_EXIT");
             }
-            mDispatcher.sendMotionEvent(mPrototype, MotionEvent.ACTION_HOVER_EXIT,
-                    mPointerIdBits, mPolicyFlags);
+            mDispatcher.sendMotionEvent(
+                    mPrototype,
+                    MotionEvent.ACTION_HOVER_EXIT,
+                    mRawEvent,
+                    mPointerIdBits,
+                    mPolicyFlags);
             if (!mSendTouchExplorationEndDelayed.isPending()) {
                 mSendTouchExplorationEndDelayed.cancel();
                 mSendTouchExplorationEndDelayed.post();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
index 49938fa..f463260 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchState.java
@@ -71,6 +71,7 @@
     // Helper class to track received pointers.
     // Todo: collapse or hide this class so multiple classes don't modify it.
     private final ReceivedPointerTracker mReceivedPointerTracker;
+    private MotionEvent mLastReceivedEvent;
 
     public TouchState() {
         mReceivedPointerTracker = new ReceivedPointerTracker();
@@ -80,6 +81,10 @@
     public void clear() {
         setState(STATE_CLEAR);
         // Reset the pointer trackers.
+        if (mLastReceivedEvent != null) {
+            mLastReceivedEvent.recycle();
+            mLastReceivedEvent = null;
+        }
         mReceivedPointerTracker.clear();
     }
 
@@ -89,6 +94,10 @@
      * @param rawEvent The raw touch event.
      */
     public void onReceivedMotionEvent(MotionEvent rawEvent) {
+        if (mLastReceivedEvent != null) {
+            mLastReceivedEvent.recycle();
+        }
+        mLastReceivedEvent = MotionEvent.obtain(rawEvent);
         mReceivedPointerTracker.onMotionEvent(rawEvent);
     }
 
@@ -216,6 +225,11 @@
         return mReceivedPointerTracker;
     }
 
+    /** @return The last received event. */
+    public MotionEvent getLastReceivedEvent() {
+        return mLastReceivedEvent;
+    }
+
     /** This class tracks where and when a pointer went down. It does not track its movement. */
     class ReceivedPointerTracker {
         private static final String LOG_TAG_RECEIVED_POINTER_TRACKER = "ReceivedPointerTracker";
@@ -232,8 +246,6 @@
         // or if it goes up the next one that most recently went down.
         private int mPrimaryPointerId;
 
-        // Keep track of the last up pointer data.
-        private MotionEvent mLastReceivedEvent;
 
         ReceivedPointerTracker() {
             clear();
@@ -254,11 +266,6 @@
          * @param event The event to process.
          */
         public void onMotionEvent(MotionEvent event) {
-            if (mLastReceivedEvent != null) {
-                mLastReceivedEvent.recycle();
-            }
-            mLastReceivedEvent = MotionEvent.obtain(event);
-
             final int action = event.getActionMasked();
             switch (action) {
                 case MotionEvent.ACTION_DOWN:
@@ -279,11 +286,6 @@
             }
         }
 
-        /** @return The last received event. */
-        public MotionEvent getLastReceivedEvent() {
-            return mLastReceivedEvent;
-        }
-
         /** @return The number of received pointers that are down. */
         public int getReceivedPointerDownCount() {
             return Integer.bitCount(mReceivedPointersDown);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index fea4e90..81ce359 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -631,8 +631,9 @@
                     onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
                             providerUserId, true);
                 } else {
-                    final SuspendDialogInfo dialogInfo = mPackageManagerInternal
-                            .getSuspendedDialogInfo(providerPackage, providerUserId);
+                    final SuspendDialogInfo dialogInfo =
+                            mPackageManagerInternal.getSuspendedDialogInfo(providerPackage,
+                                    suspendingPackage, providerUserId);
                     onClickIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(
                             providerPackage, suspendingPackage, dialogInfo, providerUserId);
                 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 8e20019..b35300c 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -78,6 +78,8 @@
     private static final int THEME_ID_DARK =
             com.android.internal.R.style.Theme_DeviceDefault_Autofill_Save;
 
+    private static final int SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS = 500;
+
     public interface OnSaveListener {
         void onSave();
         void onCancel(IntentSender listener);
@@ -252,6 +254,8 @@
                         new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                                 ViewGroup.LayoutParams.WRAP_CONTENT));
                 subtitleContainer.setVisibility(View.VISIBLE);
+                subtitleContainer.setScrollBarDefaultDelayBeforeFade(
+                        SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS);
             }
             if (sDebug) Slog.d(TAG, "on constructor: title=" + mTitle + ", subTitle=" + mSubTitle);
         }
@@ -429,6 +433,9 @@
                     saveUiView.findViewById(R.id.autofill_save_custom_subtitle);
             subtitleContainer.addView(customSubtitleView);
             subtitleContainer.setVisibility(View.VISIBLE);
+            subtitleContainer.setScrollBarDefaultDelayBeforeFade(
+                    SCROLL_BAR_DEFAULT_DELAY_BEFORE_FADE_MS);
+
             return true;
         } catch (Exception e) {
             Slog.e(TAG, "Error applying custom description. ", e);
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 80bc1af..4e80977 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -48,10 +48,12 @@
         ":services.core.protolog.json",
     ],
     cmd: "cp $(location :generate-protolog.json) $(out) && " +
-      "{ diff $(out) $(location :services.core.protolog.json) >/dev/null 2>&1 || " +
-      "{ echo -e '##### ProtoLog viewer config is stale. ### \nRun: \n " +
-      "cp $(location :generate-protolog.json) " +
-      "$(location :services.core.protolog.json)\n' >&2 && false; } }",
+      "{ ! (diff $(out) $(location :services.core.protolog.json) | grep -q '^<') || " +
+      "{ echo -e '\\n\\n################################################################\\n#\\n" +
+      "#  ERROR: ProtoLog viewer config is stale.  To update it, run:\\n#\\n" +
+      "#  cp $(location :generate-protolog.json) " +
+      "$(location :services.core.protolog.json)\\n#\\n" +
+      "################################################################\\n\\n' >&2 && false; } }",
     out: ["services.core.protolog.json"],
 }
 
@@ -106,7 +108,7 @@
         "android.hardware.biometrics.fingerprint-V2.1-java",
         "android.hardware.oemlock-V1.0-java",
         "android.hardware.tetheroffload.control-V1.0-java",
-        "android.hardware.vibrator-V1.0-java",
+        "android.hardware.vibrator-V1.4-java",
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
diff --git a/services/core/java/com/android/server/AnimationThread.java b/services/core/java/com/android/server/AnimationThread.java
index c607b1e..fad743e 100644
--- a/services/core/java/com/android/server/AnimationThread.java
+++ b/services/core/java/com/android/server/AnimationThread.java
@@ -64,7 +64,7 @@
      */
     @VisibleForTesting
     public static void dispose() {
-        synchronized (DisplayThread.class) {
+        synchronized (AnimationThread.class) {
             if (sInstance == null) {
                 return;
             }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 18a8148..9acafae 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -495,7 +495,7 @@
       * arg1 = One of the NETWORK_TESTED_RESULT_* constants.
       * arg2 = NetID.
       */
-    public static final int EVENT_NETWORK_TESTED = 41;
+    private static final int EVENT_NETWORK_TESTED = 41;
 
     /**
      * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the private DNS
@@ -503,7 +503,7 @@
      * obj = PrivateDnsConfig
      * arg2 = netid
      */
-    public static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
+    private static final int EVENT_PRIVATE_DNS_CONFIG_RESOLVED = 42;
 
     /**
      * Request ConnectivityService display provisioning notification.
@@ -511,12 +511,12 @@
      * arg2    = NetID.
      * obj     = Intent to be launched when notification selected by user, null if !arg1.
      */
-    public static final int EVENT_PROVISIONING_NOTIFICATION = 43;
+    private static final int EVENT_PROVISIONING_NOTIFICATION = 43;
 
     /**
      * This event can handle dismissing notification by given network id.
      */
-    public static final int EVENT_TIMEOUT_NOTIFICATION = 44;
+    private static final int EVENT_TIMEOUT_NOTIFICATION = 44;
 
     /**
      * Used to specify whether a network should be used even if connectivity is partial.
@@ -531,13 +531,13 @@
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be shown.
      */
-    public static final int PROVISIONING_NOTIFICATION_SHOW = 1;
+    private static final int PROVISIONING_NOTIFICATION_SHOW = 1;
 
     /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
      * should be hidden.
      */
-    public static final int PROVISIONING_NOTIFICATION_HIDE = 0;
+    private static final int PROVISIONING_NOTIFICATION_HIDE = 0;
 
     private static String eventName(int what) {
         return sMagicDecoderRing.get(what, Integer.toString(what));
@@ -1938,7 +1938,7 @@
             }
         }
 
-        return mPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
+        return NetworkPolicyManagerInternal.isUidNetworkingBlocked(uid, uidRules,
                 isNetworkMetered, isBackgroundRestricted);
     }
 
@@ -2204,7 +2204,7 @@
         final String iface = networkAgent.linkProperties.getInterfaceName();
 
         final int timeout;
-        int type = ConnectivityManager.TYPE_NONE;
+        final int type;
 
         if (networkAgent.networkCapabilities.hasTransport(
                 NetworkCapabilities.TRANSPORT_CELLULAR)) {
@@ -2219,11 +2219,10 @@
                                              15);
             type = ConnectivityManager.TYPE_WIFI;
         } else {
-            // do not track any other networks
-            timeout = 0;
+            return; // do not track any other networks
         }
 
-        if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) {
+        if (timeout > 0 && iface != null) {
             try {
                 mNMS.addIdleTimer(iface, timeout, type);
             } catch (Exception e) {
@@ -2299,7 +2298,6 @@
 
     @VisibleForTesting
     protected static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
-    private static final String DEFAULT_TCP_RWND_KEY = "net.tcp.default_init_rwnd";
 
     private void updateTcpBufferSizes(String tcpBufferSizes) {
         String[] values = null;
@@ -2375,7 +2373,8 @@
     }
 
     @Override
-    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+    protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
+            @Nullable String[] args) {
         PriorityDump.dump(mPriorityDumper, fd, writer, args);
     }
 
@@ -2837,7 +2836,7 @@
 
         private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
             mNetId = nai.network.netId;
-            mNai = new AutodestructReference(nai);
+            mNai = new AutodestructReference<>(nai);
         }
 
         @Override
@@ -4292,7 +4291,7 @@
         public void onChange(boolean selfChange, Uri uri) {
             final Integer what = mUriEventMap.get(uri);
             if (what != null) {
-                mHandler.obtainMessage(what.intValue()).sendToTarget();
+                mHandler.obtainMessage(what).sendToTarget();
             } else {
                 loge("No matching event to send for URI=" + uri);
             }
@@ -4729,12 +4728,10 @@
     private static final String ATTR_MNC = "mnc";
 
     private String getProvisioningUrlBaseFromFile() {
-        FileReader fileReader = null;
-        XmlPullParser parser = null;
+        XmlPullParser parser;
         Configuration config = mContext.getResources().getConfiguration();
 
-        try {
-            fileReader = new FileReader(mProvisioningUrlFile);
+        try (FileReader fileReader = new FileReader(mProvisioningUrlFile)) {
             parser = Xml.newPullParser();
             parser.setInput(fileReader);
             XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS);
@@ -4769,12 +4766,6 @@
             loge("Xml parser exception reading Carrier Provisioning Urls file: " + e);
         } catch (IOException e) {
             loge("I/O exception reading Carrier Provisioning Urls file: " + e);
-        } finally {
-            if (fileReader != null) {
-                try {
-                    fileReader.close();
-                } catch (IOException e) {}
-            }
         }
         return null;
     }
@@ -5104,8 +5095,8 @@
         }
     }
 
-    // This checks that the passed capabilities either do not request a specific SSID/SignalStrength
-    // , or the calling app has permission to do so.
+    // This checks that the passed capabilities either do not request a
+    // specific SSID/SignalStrength, or the calling app has permission to do so.
     private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
             int callerPid, int callerUid) {
         if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
@@ -5238,7 +5229,7 @@
                 final int uid = Binder.getCallingUid();
                 Integer uidReqs = mBandwidthRequests.get(uid);
                 if (uidReqs == null) {
-                    uidReqs = new Integer(0);
+                    uidReqs = 0;
                 }
                 mBandwidthRequests.put(uid, ++uidReqs);
             }
@@ -5572,7 +5563,7 @@
     }
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
-            LinkProperties oldLp) {
+            @NonNull LinkProperties oldLp) {
         int netId = networkAgent.network.netId;
 
         // The NetworkAgentInfo does not know whether clatd is running on its network or not, or
@@ -5687,7 +5678,7 @@
      */
     private boolean updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) {
         // Compare the route diff to determine which routes should be added and removed.
-        CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>(
+        CompareResult<RouteInfo> routeDiff = new CompareResult<>(
                 oldLp != null ? oldLp.getAllRoutes() : null,
                 newLp != null ? newLp.getAllRoutes() : null);
 
@@ -5706,7 +5697,7 @@
             }
         }
         for (RouteInfo route : routeDiff.added) {
-            if (route.hasGateway() == false) continue;
+            if (!route.hasGateway()) continue;
             if (VDBG || DDBG) log("Adding Route [" + route + "] to network " + netId);
             try {
                 mNMS.addRoute(netId, route);
@@ -5935,8 +5926,8 @@
      *  3. the VPN is fully-routed
      *  4. the VPN interface is non-null
      *
-     * @See INetd#firewallAddUidInterfaceRules
-     * @See INetd#firewallRemoveUidInterfaceRules
+     * @see INetd#firewallAddUidInterfaceRules
+     * @see INetd#firewallRemoveUidInterfaceRules
      */
     private boolean requiresVpnIsolation(@NonNull NetworkAgentInfo nai, NetworkCapabilities nc,
             LinkProperties lp) {
@@ -7051,9 +7042,9 @@
     }
 
     @Override
-    public void onShellCommand(FileDescriptor in, FileDescriptor out,
-            FileDescriptor err, String[] args, ShellCallback callback,
-            ResultReceiver resultReceiver) {
+    public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
+            FileDescriptor err, @NonNull String[] args, ShellCallback callback,
+            @NonNull ResultReceiver resultReceiver) {
         (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
     }
 
diff --git a/services/core/java/com/android/server/GnssManagerService.java b/services/core/java/com/android/server/GnssManagerService.java
new file mode 100644
index 0000000..b6e619e
--- /dev/null
+++ b/services/core/java/com/android/server/GnssManagerService.java
@@ -0,0 +1,800 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.Manifest;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.location.GnssCapabilities;
+import android.location.GnssMeasurementCorrections;
+import android.location.IBatchedLocationCallback;
+import android.location.IGnssMeasurementsListener;
+import android.location.IGnssNavigationMessageListener;
+import android.location.IGnssStatusListener;
+import android.location.IGpsGeofenceHardware;
+import android.location.INetInitiatedListener;
+import android.location.Location;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.IInterface;
+import android.os.Process;
+import android.os.RemoteException;
+import android.stats.location.LocationStatsEnums;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.LocationManagerServiceUtils.LinkedListener;
+import com.android.server.LocationManagerServiceUtils.LinkedListenerBase;
+import com.android.server.location.AbstractLocationProvider;
+import com.android.server.location.CallerIdentity;
+import com.android.server.location.GnssBatchingProvider;
+import com.android.server.location.GnssCapabilitiesProvider;
+import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
+import com.android.server.location.GnssMeasurementsProvider;
+import com.android.server.location.GnssNavigationMessageProvider;
+import com.android.server.location.GnssStatusListenerHelper;
+import com.android.server.location.RemoteListenerHelper;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/** Manages Gnss providers and related Gnss functions for LocationManagerService. */
+public class GnssManagerService {
+    private static final String TAG = "LocationManagerService";
+    private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
+
+    // Providers
+    private final GnssLocationProvider mGnssLocationProvider;
+    private final GnssStatusListenerHelper mGnssStatusProvider;
+    private final GnssMeasurementsProvider mGnssMeasurementsProvider;
+    private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
+    private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
+    private final GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
+    private final GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
+    private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
+    private final GnssBatchingProvider mGnssBatchingProvider;
+
+    private final INetInitiatedListener mNetInitiatedListener;
+    private final IGpsGeofenceHardware mGpsGeofenceProxy;
+    private final LocationManagerService mLocationManagerService;
+    private final LocationUsageLogger mLocationUsageLogger;
+
+    @GuardedBy("mGnssMeasurementsListeners")
+    private final ArrayMap<IBinder,
+            LinkedListener<IGnssMeasurementsListener>>
+            mGnssMeasurementsListeners = new ArrayMap<>();
+
+    @GuardedBy("mGnssNavigationMessageListeners")
+    private final ArrayMap<
+            IBinder, LinkedListener<IGnssNavigationMessageListener>>
+            mGnssNavigationMessageListeners = new ArrayMap<>();
+
+    @GuardedBy("mGnssStatusListeners")
+    private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
+            mGnssStatusListeners = new ArrayMap<>();
+
+    @GuardedBy("mGnssBatchingLock")
+    private IBatchedLocationCallback mGnssBatchingCallback;
+
+    @GuardedBy("mGnssBatchingLock")
+    private LinkedListener<IBatchedLocationCallback>
+            mGnssBatchingDeathCallback;
+
+    @GuardedBy("mGnssBatchingLock")
+    private boolean mGnssBatchingInProgress = false;
+
+    private final Object mGnssBatchingLock = new Object();
+    private final Context mContext;
+    private final Handler mHandler;
+
+    public GnssManagerService(LocationManagerService locationManagerService,
+            Context context,
+            AbstractLocationProvider.LocationProviderManager gnssProviderManager,
+            LocationUsageLogger locationUsageLogger) {
+        this(locationManagerService, context, new GnssLocationProvider(context, gnssProviderManager,
+                FgThread.getHandler().getLooper()), locationUsageLogger);
+    }
+
+    // Can use this constructor to inject GnssLocationProvider for testing
+    @VisibleForTesting
+    GnssManagerService(LocationManagerService locationManagerService,
+            Context context,
+            GnssLocationProvider gnssLocationProvider,
+            LocationUsageLogger locationUsageLogger) {
+        mContext = context;
+        mHandler = FgThread.getHandler();
+
+        mGnssLocationProvider =
+                gnssLocationProvider;
+
+        mGnssStatusProvider = mGnssLocationProvider.getGnssStatusProvider();
+        mGnssMeasurementsProvider = mGnssLocationProvider.getGnssMeasurementsProvider();
+        mGnssMeasurementCorrectionsProvider =
+                mGnssLocationProvider.getGnssMeasurementCorrectionsProvider();
+        mGnssNavigationMessageProvider = mGnssLocationProvider.getGnssNavigationMessageProvider();
+        mGnssSystemInfoProvider = mGnssLocationProvider.getGnssSystemInfoProvider();
+        mGnssMetricsProvider = mGnssLocationProvider.getGnssMetricsProvider();
+        mGnssCapabilitiesProvider = mGnssLocationProvider.getGnssCapabilitiesProvider();
+        mGnssBatchingProvider = mGnssLocationProvider.getGnssBatchingProvider();
+
+        mNetInitiatedListener = mGnssLocationProvider.getNetInitiatedListener();
+        mGpsGeofenceProxy = mGnssLocationProvider.getGpsGeofenceProxy();
+        mLocationManagerService = locationManagerService;
+        mLocationUsageLogger = locationUsageLogger;
+
+        registerUidListener();
+    }
+
+    public static boolean isGnssSupported() {
+        return GnssLocationProvider.isSupported();
+    }
+
+    private boolean hasGnssPermissions(String packageName) {
+        mContext.enforceCallingPermission(
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                "Fine location permission not granted.");
+
+        int uid = Binder.getCallingUid();
+        long identity = Binder.clearCallingIdentity();
+        try {
+            return mContext.getSystemService(
+                    AppOpsManager.class).checkOp(AppOpsManager.OP_FINE_LOCATION, uid, packageName)
+                    == AppOpsManager.MODE_ALLOWED;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    public GnssLocationProvider getGnssLocationProvider() {
+        return mGnssLocationProvider;
+    }
+
+    public IGpsGeofenceHardware getGpsGeofenceProxy() {
+        return mGpsGeofenceProxy;
+    }
+
+    /**
+     * Get year of GNSS hardware.
+     *
+     * @return year of GNSS hardware as an int if possible, otherwise zero
+     */
+    public int getGnssYearOfHardware() {
+        if (mGnssSystemInfoProvider != null) {
+            return mGnssSystemInfoProvider.getGnssYearOfHardware();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Get model name of GNSS hardware.
+     *
+     * @return GNSS hardware model name as a string if possible, otherwise null
+     */
+    public String getGnssHardwareModelName() {
+        if (mGnssSystemInfoProvider != null) {
+            return mGnssSystemInfoProvider.getGnssHardwareModelName();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get GNSS hardware capabilities. The capabilities are described in {@link
+     * android.location.GnssCapabilities} and their integer values correspond to the
+     * bit positions in the returned {@code long} value.
+     *
+     * @param packageName name of requesting package
+     * @return capabilities supported by the GNSS chipset
+     */
+    public long getGnssCapabilities(String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
+        if (!hasGnssPermissions(packageName) || mGnssCapabilitiesProvider == null) {
+            return GnssCapabilities.INVALID_CAPABILITIES;
+        }
+        return mGnssCapabilitiesProvider.getGnssCapabilities();
+    }
+
+    /**
+     * Get size of GNSS batch (GNSS location results are batched together for power savings).
+     * Requires LOCATION_HARDWARE and GNSS permissions.
+     *
+     * @param packageName name of requesting package
+     * @return size of the GNSS batch collection
+     */
+    public int getGnssBatchSize(String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "getGnssBatchSize called without GNSS permissions");
+            return 0;
+        }
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not get GNSS batch size. GNSS batching provider "
+                            + "not available.");
+            return 0;
+        }
+
+        synchronized (mGnssBatchingLock) {
+            return mGnssBatchingProvider.getBatchSize();
+        }
+    }
+
+    /**
+     * Starts GNSS batch collection. GNSS positions are collected in a batch before being delivered
+     * as a collection.
+     *
+     * @param periodNanos    duration over which to collect GPS positions before delivering as a
+     *                       batch
+     * @param wakeOnFifoFull specifying whether to wake on full queue
+     * @param packageName    name of requesting package
+     * @return true of batch started successfully, false otherwise
+     */
+    public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "startGnssBatch called without GNSS permissions");
+            return false;
+        }
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not start GNSS batching. GNSS batching provider "
+                            + "not available.");
+            return false;
+        }
+
+        synchronized (mGnssBatchingLock) {
+            if (mGnssBatchingInProgress) {
+                // Current design does not expect multiple starts to be called repeatedly
+                Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
+                // Try to clean up anyway, and continue
+                stopGnssBatch();
+            }
+
+            mGnssBatchingInProgress = true;
+            return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
+        }
+    }
+
+    /**
+     * Adds a GNSS batching callback for delivering GNSS location batch results.
+     *
+     * @param callback    called when batching operation is complete to deliver GPS positions
+     * @param packageName name of requesting package
+     * @return true if callback is successfully added, false otherwise
+     */
+    public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "addGnssBatchingCallback called without GNSS permissions");
+            return false;
+        }
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not add GNSS batching callback. GNSS batching provider "
+                            + "not available.");
+            return false;
+        }
+
+        CallerIdentity callerIdentity =
+                new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+        synchronized (mGnssBatchingLock) {
+            mGnssBatchingCallback = callback;
+            mGnssBatchingDeathCallback =
+                    new LocationManagerServiceUtils.LinkedListener<>(
+                            callback,
+                            "BatchedLocationCallback",
+                            callerIdentity,
+                            (IBatchedLocationCallback listener) -> {
+                                stopGnssBatch();
+                                removeGnssBatchingCallback();
+                            });
+            if (!mGnssBatchingDeathCallback.linkToListenerDeathNotificationLocked(
+                    callback.asBinder())) {
+                return false;
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Force flush GNSS location results from batch.
+     *
+     * @param packageName name of requesting package
+     */
+    public void flushGnssBatch(String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "flushGnssBatch called without GNSS permissions");
+            return;
+        }
+
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not flush GNSS batch. GNSS batching provider "
+                            + "not available.");
+            return;
+        }
+
+        synchronized (mGnssBatchingLock) {
+            if (!mGnssBatchingInProgress) {
+                Log.w(TAG, "flushGnssBatch called with no batch in progress");
+            }
+            mGnssBatchingProvider.flush();
+        }
+    }
+
+    /**
+     * Removes GNSS batching callback.
+     */
+    public void removeGnssBatchingCallback() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not add GNSS batching callback. GNSS batching provider "
+                            + "not available.");
+            return;
+        }
+
+        synchronized (mGnssBatchingLock) {
+            mGnssBatchingDeathCallback.unlinkFromListenerDeathNotificationLocked(
+                    mGnssBatchingCallback.asBinder());
+            mGnssBatchingCallback = null;
+            mGnssBatchingDeathCallback = null;
+        }
+    }
+
+    /**
+     * Stop GNSS batch collection.
+     *
+     * @return true if GNSS batch successfully stopped, false otherwise
+     */
+    public boolean stopGnssBatch() {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to access hardware batching");
+
+        if (mGnssBatchingProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not stop GNSS batch. GNSS batching provider "
+                            + "not available.");
+            return false;
+        }
+        synchronized (mGnssBatchingLock) {
+            mGnssBatchingInProgress = false;
+            return mGnssBatchingProvider.stop();
+        }
+    }
+
+    private void registerUidListener() {
+        mContext.getSystemService(
+                ActivityManager.class).addOnUidImportanceListener(
+                    (uid, importance) -> {
+                        // listener invoked on ui thread, move to our thread to reduce risk
+                        // of blocking ui thread
+                        mHandler.post(
+                                () -> {
+                                    onForegroundChanged(uid,
+                                            LocationManagerServiceUtils.isImportanceForeground(
+                                                    importance));
+                                });
+                    },
+                ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+    }
+
+    private void onForegroundChanged(int uid, boolean foreground) {
+        synchronized (mGnssMeasurementsListeners) {
+            updateListenersOnForegroundChangedLocked(
+                    mGnssMeasurementsListeners,
+                    mGnssMeasurementsProvider,
+                    IGnssMeasurementsListener.Stub::asInterface,
+                    uid,
+                    foreground);
+        }
+        synchronized (mGnssNavigationMessageListeners) {
+            updateListenersOnForegroundChangedLocked(
+                    mGnssNavigationMessageListeners,
+                    mGnssNavigationMessageProvider,
+                    IGnssNavigationMessageListener.Stub::asInterface,
+                    uid,
+                    foreground);
+        }
+        synchronized (mGnssStatusListeners) {
+            updateListenersOnForegroundChangedLocked(
+                    mGnssStatusListeners,
+                    mGnssStatusProvider,
+                    IGnssStatusListener.Stub::asInterface,
+                    uid,
+                    foreground);
+        }
+    }
+
+    private <TListener extends IInterface> void updateListenersOnForegroundChangedLocked(
+            ArrayMap<IBinder, ? extends LinkedListenerBase>
+                    gnssDataListeners,
+            RemoteListenerHelper<TListener> gnssDataProvider,
+            Function<IBinder, TListener> mapBinderToListener,
+            int uid,
+            boolean foreground) {
+        for (Map.Entry<IBinder, ? extends LinkedListenerBase> entry :
+                gnssDataListeners.entrySet()) {
+            LinkedListenerBase linkedListener = entry.getValue();
+            CallerIdentity callerIdentity = linkedListener.getCallerIdentity();
+            if (callerIdentity.mUid != uid) {
+                continue;
+            }
+
+            if (D) {
+                Log.d(
+                        TAG,
+                        linkedListener.getListenerName()
+                                + " from uid "
+                                + uid
+                                + " is now "
+                                + LocationManagerServiceUtils.foregroundAsString(foreground));
+            }
+
+            TListener listener = mapBinderToListener.apply(entry.getKey());
+            if (foreground || mLocationManagerService.isThrottlingExemptLocked(callerIdentity)) {
+                gnssDataProvider.addListener(listener, callerIdentity);
+            } else {
+                gnssDataProvider.removeListener(listener);
+            }
+        }
+    }
+
+    private <TListener extends IInterface> boolean addGnssDataListenerLocked(
+            TListener listener,
+            String packageName,
+            String listenerName,
+            RemoteListenerHelper<TListener> gnssDataProvider,
+            ArrayMap<IBinder,
+                    LinkedListener<TListener>> gnssDataListeners,
+            Consumer<TListener> binderDeathCallback) {
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "addGnssDataListenerLocked called without GNSS permissions");
+            return false;
+        }
+
+        if (gnssDataProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not add GNSS data listener. GNSS data provider "
+                            + "not available.");
+            return false;
+        }
+
+        CallerIdentity callerIdentity =
+                new CallerIdentity(Binder.getCallingUid(), Binder.getCallingPid(), packageName);
+        LinkedListener<TListener> linkedListener =
+                new LocationManagerServiceUtils.LinkedListener<>(
+                        listener, listenerName, callerIdentity, binderDeathCallback);
+        IBinder binder = listener.asBinder();
+        if (!linkedListener.linkToListenerDeathNotificationLocked(binder)) {
+            return false;
+        }
+
+        gnssDataListeners.put(binder, linkedListener);
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (gnssDataProvider == mGnssMeasurementsProvider
+                    || gnssDataProvider == mGnssStatusProvider) {
+                mLocationUsageLogger.logLocationApiUsage(
+                        LocationStatsEnums.USAGE_STARTED,
+                        gnssDataProvider == mGnssMeasurementsProvider
+                                ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
+                                : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
+                        packageName,
+                        /* LocationRequest= */ null,
+                        /* hasListener= */ true,
+                        /* hasIntent= */ false,
+                        /* geofence= */ null,
+                        LocationManagerServiceUtils.getPackageImportance(packageName,
+                                mContext));
+            }
+            if (mLocationManagerService.isThrottlingExemptLocked(callerIdentity)
+                    || LocationManagerServiceUtils.isImportanceForeground(
+                    LocationManagerServiceUtils.getPackageImportance(packageName, mContext))) {
+                gnssDataProvider.addListener(listener, callerIdentity);
+            }
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private <TListener extends IInterface> void removeGnssDataListener(
+            TListener listener,
+            RemoteListenerHelper<TListener> gnssDataProvider,
+            ArrayMap<IBinder,
+                    LinkedListener<TListener>> gnssDataListeners) {
+        if (gnssDataProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not remove GNSS data listener. GNSS data provider "
+                            + "not available.");
+            return;
+        }
+
+        IBinder binder = listener.asBinder();
+        LinkedListener<TListener> linkedListener =
+                gnssDataListeners.remove(binder);
+        if (linkedListener == null) {
+            return;
+        }
+        long identity = Binder.clearCallingIdentity();
+        try {
+            if (gnssDataProvider == mGnssMeasurementsProvider
+                    || gnssDataProvider == mGnssStatusProvider) {
+                mLocationUsageLogger.logLocationApiUsage(
+                        LocationStatsEnums.USAGE_ENDED,
+                        gnssDataProvider == mGnssMeasurementsProvider
+                                ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
+                                : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
+                        linkedListener.getCallerIdentity().mPackageName,
+                        /* LocationRequest= */ null,
+                        /* hasListener= */ true,
+                        /* hasIntent= */ false,
+                        /* geofence= */ null,
+                        LocationManagerServiceUtils.getPackageImportance(
+                                linkedListener.getCallerIdentity().mPackageName, mContext));
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+        linkedListener.unlinkFromListenerDeathNotificationLocked(binder);
+        gnssDataProvider.removeListener(listener);
+    }
+
+    /**
+     * Registers listener for GNSS status changes.
+     *
+     * @param listener    called when GNSS status changes
+     * @param packageName name of requesting package
+     * @return true if listener is successfully registered, false otherwise
+     */
+    public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
+        synchronized (mGnssStatusListeners) {
+            return addGnssDataListenerLocked(
+                    listener,
+                    packageName,
+                    "GnssStatusListener",
+                    mGnssStatusProvider,
+                    mGnssStatusListeners,
+                    this::unregisterGnssStatusCallback);
+        }
+    }
+
+    /**
+     * Unregisters listener for GNSS status changes.
+     *
+     * @param listener called when GNSS status changes
+     */
+    public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
+        synchronized (mGnssStatusListeners) {
+            removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
+        }
+    }
+
+    /**
+     * Adds a GNSS measurements listener.
+     *
+     * @param listener    called when GNSS measurements are received
+     * @param packageName name of requesting package
+     * @return true if listener is successfully added, false otherwise
+     */
+    public boolean addGnssMeasurementsListener(
+            IGnssMeasurementsListener listener, String packageName) {
+        synchronized (mGnssMeasurementsListeners) {
+            return addGnssDataListenerLocked(
+                    listener,
+                    packageName,
+                    "GnssMeasurementsListener",
+                    mGnssMeasurementsProvider,
+                    mGnssMeasurementsListeners,
+                    this::removeGnssMeasurementsListener);
+        }
+    }
+
+    /**
+     * Injects GNSS measurement corrections.
+     *
+     * @param measurementCorrections GNSS measurement corrections
+     * @param packageName            name of requesting package
+     */
+    public void injectGnssMeasurementCorrections(
+            GnssMeasurementCorrections measurementCorrections, String packageName) {
+        mContext.enforceCallingPermission(
+                android.Manifest.permission.LOCATION_HARDWARE,
+                "Location Hardware permission not granted to inject GNSS measurement corrections.");
+        if (!hasGnssPermissions(packageName)) {
+            Log.e(TAG, "Can not inject GNSS corrections due to no permission.");
+            return;
+        }
+        if (mGnssMeasurementCorrectionsProvider == null) {
+            Log.e(
+                    TAG,
+                    "Can not inject GNSS corrections. GNSS measurement corrections provider "
+                            + "not available.");
+            return;
+        }
+        mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
+                measurementCorrections);
+    }
+
+    /**
+     * Removes a GNSS measurements listener.
+     *
+     * @param listener called when GNSS measurements are received
+     */
+    public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
+        synchronized (mGnssMeasurementsListeners) {
+            removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
+        }
+    }
+
+    /**
+     * Adds a GNSS navigation message listener.
+     *
+     * @param listener    called when navigation message is received
+     * @param packageName name of requesting package
+     * @return true if listener is successfully added, false otherwise
+     */
+    public boolean addGnssNavigationMessageListener(
+            IGnssNavigationMessageListener listener, String packageName) {
+        synchronized (mGnssNavigationMessageListeners) {
+            return addGnssDataListenerLocked(
+                    listener,
+                    packageName,
+                    "GnssNavigationMessageListener",
+                    mGnssNavigationMessageProvider,
+                    mGnssNavigationMessageListeners,
+                    this::removeGnssNavigationMessageListener);
+        }
+    }
+
+    /**
+     * Removes a GNSS navigation message listener.
+     *
+     * @param listener called when navigation message is received
+     */
+    public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
+        removeGnssDataListener(
+                listener, mGnssNavigationMessageProvider, mGnssNavigationMessageListeners);
+    }
+
+    /**
+     * Send Ni Response, indicating a location request initiated by a network carrier.
+     */
+    public boolean sendNiResponse(int notifId, int userResponse) {
+        if (Binder.getCallingUid() != Process.myUid()) {
+            throw new SecurityException(
+                    "calling sendNiResponse from outside of the system is not allowed");
+        }
+        try {
+            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
+            return false;
+        }
+    }
+
+    /**
+     * Report location results to GNSS batching listener.
+     *
+     * @param locations batch of locations to report to GNSS batching callback
+     */
+    public void onReportLocation(List<Location> locations) {
+        if (mGnssBatchingCallback == null) {
+            Log.e(TAG, "reportLocationBatch() called without active Callback");
+            return;
+        }
+
+        try {
+            mGnssBatchingCallback.onLocationBatch(locations);
+        } catch (RemoteException e) {
+            Log.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
+        }
+    }
+
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+        IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
+
+        if (args.length > 0 && args[0].equals("--gnssmetrics")) {
+            if (mGnssMetricsProvider != null) {
+                pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
+            }
+            return;
+        }
+
+        ipw.println("GnssMeasurement Listeners:");
+        ipw.increaseIndent();
+        synchronized (mGnssMeasurementsListeners) {
+            for (LinkedListenerBase listener :
+                    mGnssMeasurementsListeners
+                            .values()) {
+                ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
+                        listener.mCallerIdentity));
+            }
+        }
+        ipw.decreaseIndent();
+
+        ipw.println("GnssNavigationMessage Listeners:");
+        ipw.increaseIndent();
+        synchronized (mGnssNavigationMessageListeners) {
+            for (LinkedListenerBase listener :
+                    mGnssNavigationMessageListeners.values()) {
+                ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
+                        listener.mCallerIdentity));
+            }
+        }
+        ipw.decreaseIndent();
+
+        ipw.println("GnssStatus Listeners:");
+        ipw.increaseIndent();
+        synchronized (mGnssStatusListeners) {
+            for (LinkedListenerBase listener :
+                    mGnssStatusListeners.values()) {
+                ipw.println(listener + ": " + mLocationManagerService.isThrottlingExemptLocked(
+                        listener.mCallerIdentity));
+            }
+        }
+        ipw.decreaseIndent();
+
+        synchronized (mGnssBatchingLock) {
+            if (mGnssBatchingInProgress) {
+                ipw.println("GNSS batching in progress");
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 69f226f6..35a06a9 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -49,16 +49,13 @@
 import android.location.Criteria;
 import android.location.GeocoderParams;
 import android.location.Geofence;
-import android.location.GnssCapabilities;
 import android.location.GnssMeasurementCorrections;
 import android.location.IBatchedLocationCallback;
 import android.location.IGnssMeasurementsListener;
 import android.location.IGnssNavigationMessageListener;
 import android.location.IGnssStatusListener;
-import android.location.IGpsGeofenceHardware;
 import android.location.ILocationListener;
 import android.location.ILocationManager;
-import android.location.INetInitiatedListener;
 import android.location.Location;
 import android.location.LocationManager;
 import android.location.LocationRequest;
@@ -67,7 +64,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.IInterface;
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
 import android.os.PowerManagerInternal;
@@ -81,7 +77,6 @@
 import android.provider.Settings;
 import android.stats.location.LocationStatsEnums;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Log;
@@ -102,13 +97,6 @@
 import com.android.server.location.GeocoderProxy;
 import com.android.server.location.GeofenceManager;
 import com.android.server.location.GeofenceProxy;
-import com.android.server.location.GnssBatchingProvider;
-import com.android.server.location.GnssCapabilitiesProvider;
-import com.android.server.location.GnssLocationProvider;
-import com.android.server.location.GnssMeasurementCorrectionsProvider;
-import com.android.server.location.GnssMeasurementsProvider;
-import com.android.server.location.GnssNavigationMessageProvider;
-import com.android.server.location.GnssStatusListenerHelper;
 import com.android.server.location.LocationBlacklist;
 import com.android.server.location.LocationFudger;
 import com.android.server.location.LocationProviderProxy;
@@ -117,7 +105,6 @@
 import com.android.server.location.LocationRequestStatistics.PackageStatistics;
 import com.android.server.location.MockProvider;
 import com.android.server.location.PassiveProvider;
-import com.android.server.location.RemoteListenerHelper;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 
 import java.io.ByteArrayOutputStream;
@@ -132,9 +119,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.NoSuchElementException;
-import java.util.function.Consumer;
-import java.util.function.Function;
 
 /**
  * The service class that manages LocationProviders and issues location
@@ -197,17 +181,13 @@
     private GeofenceManager mGeofenceManager;
     private LocationFudger mLocationFudger;
     private GeocoderProxy mGeocodeProvider;
-    private GnssStatusListenerHelper mGnssStatusProvider;
-    private INetInitiatedListener mNetInitiatedListener;
-    private PassiveProvider mPassiveProvider;  // track passive provider for special cases
+    @Nullable
+    private GnssManagerService mGnssManagerService;
+    private PassiveProvider mPassiveProvider; // track passive provider for special cases
     private LocationBlacklist mBlacklist;
-    private GnssMeasurementsProvider mGnssMeasurementsProvider;
-    private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
-    private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     @GuardedBy("mLock")
     private String mExtraLocationControllerPackage;
     private boolean mExtraLocationControllerPackageEnabled;
-    private IGpsGeofenceHardware mGpsGeofenceProxy;
 
     // list of currently active providers
     @GuardedBy("mLock")
@@ -239,32 +219,10 @@
 
     private final ArraySet<String> mIgnoreSettingsPackageWhitelist = new ArraySet<>();
 
-    @GuardedBy("mLock")
-    private final ArrayMap<IBinder, LinkedListener<IGnssMeasurementsListener>>
-            mGnssMeasurementsListeners = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private final ArrayMap<IBinder, LinkedListener<IGnssNavigationMessageListener>>
-            mGnssNavigationMessageListeners = new ArrayMap<>();
-    @GuardedBy("mLock")
-    private final ArrayMap<IBinder, LinkedListener<IGnssStatusListener>>
-            mGnssStatusListeners = new ArrayMap<>();
-
     // current active user on the device - other users are denied location data
     private int mCurrentUserId = UserHandle.USER_SYSTEM;
     private int[] mCurrentUserProfiles = new int[]{UserHandle.USER_SYSTEM};
 
-    private GnssLocationProvider.GnssSystemInfoProvider mGnssSystemInfoProvider;
-    private GnssLocationProvider.GnssMetricsProvider mGnssMetricsProvider;
-    private GnssCapabilitiesProvider mGnssCapabilitiesProvider;
-
-    private GnssBatchingProvider mGnssBatchingProvider;
-    @GuardedBy("mLock")
-    private IBatchedLocationCallback mGnssBatchingCallback;
-    @GuardedBy("mLock")
-    private LinkedListener<IBatchedLocationCallback> mGnssBatchingDeathCallback;
-    @GuardedBy("mLock")
-    private boolean mGnssBatchingInProgress = false;
-
     @GuardedBy("mLock")
     @PowerManager.LocationPowerSaveMode
     private int mBatterySaverMode;
@@ -287,7 +245,7 @@
                         com.android.internal.R.array.config_locationProviderPackageNames));
         permissionManagerInternal.setLocationExtraPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
-                      com.android.internal.R.array.config_locationExtraPackageNames));
+                        com.android.internal.R.array.config_locationExtraPackageNames));
 
         // most startup is deferred until systemRunning()
     }
@@ -567,7 +525,7 @@
 
     @GuardedBy("mLock")
     private void onUidImportanceChangedLocked(int uid, int importance) {
-        boolean foreground = isImportanceForeground(importance);
+        boolean foreground = LocationManagerServiceUtils.isImportanceForeground(importance);
         HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
         for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
             String provider = entry.getKey();
@@ -576,7 +534,8 @@
                         && record.mIsForegroundUid != foreground) {
                     if (D) {
                         Log.d(TAG, "request from uid " + uid + " is now "
-                                + foregroundAsString(foreground));
+                                + LocationManagerServiceUtils.foregroundAsString(
+                                foreground));
                     }
                     record.updateForeground(foreground);
 
@@ -589,51 +548,6 @@
         for (String provider : affectedProviders) {
             applyRequirementsLocked(provider);
         }
-
-        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssMeasurementsListeners,
-                mGnssMeasurementsProvider, IGnssMeasurementsListener.Stub::asInterface,
-                uid, foreground);
-
-        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssNavigationMessageListeners,
-                mGnssNavigationMessageProvider, IGnssNavigationMessageListener.Stub::asInterface,
-                uid, foreground);
-
-        updateGnssDataProviderOnUidImportanceChangedLocked(mGnssStatusListeners,
-                mGnssStatusProvider, IGnssStatusListener.Stub::asInterface, uid, foreground);
-    }
-
-    @GuardedBy("mLock")
-    private <TListener extends IInterface> void updateGnssDataProviderOnUidImportanceChangedLocked(
-            ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners,
-            RemoteListenerHelper<TListener> gnssDataProvider,
-            Function<IBinder, TListener> mapBinderToListener, int uid, boolean foreground) {
-        for (Entry<IBinder, ? extends LinkedListenerBase> entry : gnssDataListeners.entrySet()) {
-            LinkedListenerBase linkedListener = entry.getValue();
-            CallerIdentity callerIdentity = linkedListener.mCallerIdentity;
-            if (callerIdentity.mUid != uid) {
-                continue;
-            }
-
-            if (D) {
-                Log.d(TAG, linkedListener.mListenerName + " from uid "
-                        + uid + " is now " + foregroundAsString(foreground));
-            }
-
-            TListener listener = mapBinderToListener.apply(entry.getKey());
-            if (foreground || isThrottlingExemptLocked(callerIdentity)) {
-                gnssDataProvider.addListener(listener, callerIdentity);
-            } else {
-                gnssDataProvider.removeListener(listener);
-            }
-        }
-    }
-
-    private static String foregroundAsString(boolean foreground) {
-        return foreground ? "foreground" : "background";
-    }
-
-    private static boolean isImportanceForeground(int importance) {
-        return importance <= FOREGROUND_IMPORTANCE_CUTOFF;
     }
 
     @GuardedBy("mLock")
@@ -768,28 +682,15 @@
         mPassiveProvider = new PassiveProvider(mContext, passiveProviderManager);
         passiveProviderManager.attachLocked(mPassiveProvider);
 
-        if (GnssLocationProvider.isSupported()) {
-            // Create a gps location provider
+        if (GnssManagerService.isGnssSupported()) {
+            // Create a gps location provider manager
             LocationProvider gnssProviderManager = new LocationProvider(GPS_PROVIDER, true);
             mRealProviders.add(gnssProviderManager);
             addProviderLocked(gnssProviderManager);
 
-            GnssLocationProvider gnssProvider = new GnssLocationProvider(mContext,
-                    gnssProviderManager,
-                    mHandler.getLooper());
-            gnssProviderManager.attachLocked(gnssProvider);
-
-            mGnssSystemInfoProvider = gnssProvider.getGnssSystemInfoProvider();
-            mGnssBatchingProvider = gnssProvider.getGnssBatchingProvider();
-            mGnssMetricsProvider = gnssProvider.getGnssMetricsProvider();
-            mGnssCapabilitiesProvider = gnssProvider.getGnssCapabilitiesProvider();
-            mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
-            mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
-            mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
-            mGnssMeasurementCorrectionsProvider =
-                    gnssProvider.getGnssMeasurementCorrectionsProvider();
-            mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
-            mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
+            mGnssManagerService = new GnssManagerService(this, mContext, gnssProviderManager,
+                    mLocationUsageLogger);
+            gnssProviderManager.attachLocked(mGnssManagerService.getGnssLocationProvider());
         }
 
         /*
@@ -857,15 +758,17 @@
             Slog.e(TAG, "no geocoder provider found");
         }
 
-        // bind to geofence provider
-        GeofenceProxy provider = GeofenceProxy.createAndBind(
-                mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
-                com.android.internal.R.string.config_geofenceProviderPackageName,
-                com.android.internal.R.array.config_locationProviderPackageNames,
-                mGpsGeofenceProxy,
-                null);
-        if (provider == null) {
-            Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
+        if (mGnssManagerService != null) {
+            // bind to geofence provider
+            GeofenceProxy provider = GeofenceProxy.createAndBind(
+                    mContext, com.android.internal.R.bool.config_enableGeofenceOverlay,
+                    com.android.internal.R.string.config_geofenceProviderPackageName,
+                    com.android.internal.R.array.config_locationProviderPackageNames,
+                    mGnssManagerService.getGpsGeofenceProxy(),
+                    null);
+            if (provider == null) {
+                Slog.d(TAG, "Unable to bind FLP Geofence proxy.");
+            }
         }
 
         // bind to hardware activity recognition
@@ -939,7 +842,10 @@
         }
     }
 
-    private class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
+    /**
+     * Location provider manager, manages a LocationProvider.
+     */
+    class LocationProvider implements AbstractLocationProvider.LocationProviderManager {
 
         private final String mName;
 
@@ -948,7 +854,8 @@
 
         // remember to clear binder identity before invoking any provider operation
         @GuardedBy("mLock")
-        @Nullable protected AbstractLocationProvider mProvider;
+        @Nullable
+        protected AbstractLocationProvider mProvider;
 
         @GuardedBy("mLock")
         private boolean mUseable;  // combined state
@@ -958,7 +865,8 @@
         private boolean mEnabled;  // state of provider
 
         @GuardedBy("mLock")
-        @Nullable private ProviderProperties mProperties;
+        @Nullable
+        private ProviderProperties mProperties;
 
         private LocationProvider(String name) {
             this(name, false);
@@ -1095,6 +1003,9 @@
 
         @Override
         public void onReportLocation(List<Location> locations) {
+            if (mGnssManagerService == null) {
+                return;
+            }
             synchronized (mLock) {
                 LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
                 if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
@@ -1102,16 +1013,7 @@
                     return;
                 }
 
-                if (mGnssBatchingCallback == null) {
-                    Slog.e(TAG, "reportLocationBatch() called without active Callback");
-                    return;
-                }
-
-                try {
-                    mGnssBatchingCallback.onLocationBatch(locations);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
-                }
+                mGnssManagerService.onReportLocation(locations);
             }
         }
 
@@ -1300,7 +1202,8 @@
      * A wrapper class holding either an ILocationListener or a PendingIntent to receive
      * location updates.
      */
-    private final class Receiver extends LinkedListenerBase implements PendingIntent.OnFinished {
+    private final class Receiver extends LocationManagerServiceUtils.LinkedListenerBase implements
+            PendingIntent.OnFinished {
         private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
         private final int mAllowedResolutionLevel;  // resolution level allowed to receiver
 
@@ -1614,146 +1517,45 @@
 
     @Override
     public int getGnssYearOfHardware() {
-        if (mGnssSystemInfoProvider != null) {
-            return mGnssSystemInfoProvider.getGnssYearOfHardware();
-        } else {
-            return 0;
-        }
+        return mGnssManagerService == null ? 0 : mGnssManagerService.getGnssYearOfHardware();
     }
 
     @Override
     @Nullable
     public String getGnssHardwareModelName() {
-        if (mGnssSystemInfoProvider != null) {
-            return mGnssSystemInfoProvider.getGnssHardwareModelName();
-        } else {
-            return null;
-        }
-    }
-
-    private boolean hasGnssPermissions(String packageName) {
-        synchronized (mLock) {
-            int allowedResolutionLevel = getCallerAllowedResolutionLevel();
-            checkResolutionLevelIsSufficientForProviderUseLocked(
-                    allowedResolutionLevel,
-                    GPS_PROVIDER);
-
-            int pid = Binder.getCallingPid();
-            int uid = Binder.getCallingUid();
-            long identity = Binder.clearCallingIdentity();
-            try {
-                return checkLocationAccess(pid, uid, packageName, allowedResolutionLevel);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
+        return mGnssManagerService == null ? "" : mGnssManagerService.getGnssHardwareModelName();
     }
 
     @Override
     public int getGnssBatchSize(String packageName) {
-        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to access hardware batching");
-
-        if (hasGnssPermissions(packageName) && mGnssBatchingProvider != null) {
-            return mGnssBatchingProvider.getBatchSize();
-        } else {
-            return 0;
-        }
+        return mGnssManagerService == null ? 0 : mGnssManagerService.getGnssBatchSize(packageName);
     }
 
     @Override
     public boolean addGnssBatchingCallback(IBatchedLocationCallback callback, String packageName) {
-        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to access hardware batching");
-
-        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
-            return false;
-        }
-
-        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
-                Binder.getCallingPid(), packageName);
-        synchronized (mLock) {
-            mGnssBatchingCallback = callback;
-            mGnssBatchingDeathCallback =  new LinkedListener<>(callback,
-                    "BatchedLocationCallback", callerIdentity,
-                    (IBatchedLocationCallback listener) -> {
-                        stopGnssBatch();
-                        removeGnssBatchingCallback();
-                    });
-            if (!linkToListenerDeathNotificationLocked(callback.asBinder(),
-                    mGnssBatchingDeathCallback)) {
-                return false;
-            }
-            return true;
-        }
+        return mGnssManagerService == null ? false : mGnssManagerService.addGnssBatchingCallback(
+                callback, packageName);
     }
 
     @Override
     public void removeGnssBatchingCallback() {
-        synchronized (mLock) {
-            unlinkFromListenerDeathNotificationLocked(mGnssBatchingCallback.asBinder(),
-                    mGnssBatchingDeathCallback);
-            mGnssBatchingCallback = null;
-            mGnssBatchingDeathCallback = null;
-        }
+        if (mGnssManagerService != null) mGnssManagerService.removeGnssBatchingCallback();
     }
 
     @Override
     public boolean startGnssBatch(long periodNanos, boolean wakeOnFifoFull, String packageName) {
-        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to access hardware batching");
-
-        if (!hasGnssPermissions(packageName) || mGnssBatchingProvider == null) {
-            return false;
-        }
-
-        synchronized (mLock) {
-            if (mGnssBatchingInProgress) {
-                // Current design does not expect multiple starts to be called repeatedly
-                Log.e(TAG, "startGnssBatch unexpectedly called w/o stopping prior batch");
-                // Try to clean up anyway, and continue
-                stopGnssBatch();
-            }
-
-            mGnssBatchingInProgress = true;
-            return mGnssBatchingProvider.start(periodNanos, wakeOnFifoFull);
-        }
+        return mGnssManagerService == null ? false : mGnssManagerService.startGnssBatch(periodNanos,
+                wakeOnFifoFull, packageName);
     }
 
     @Override
     public void flushGnssBatch(String packageName) {
-        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to access hardware batching");
-
-        if (!hasGnssPermissions(packageName)) {
-            Log.e(TAG, "flushGnssBatch called without GNSS permissions");
-            return;
-        }
-
-        synchronized (mLock) {
-            if (!mGnssBatchingInProgress) {
-                Log.w(TAG, "flushGnssBatch called with no batch in progress");
-            }
-
-            if (mGnssBatchingProvider != null) {
-                mGnssBatchingProvider.flush();
-            }
-        }
+        if (mGnssManagerService != null) mGnssManagerService.flushGnssBatch(packageName);
     }
 
     @Override
     public boolean stopGnssBatch() {
-        mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to access hardware batching");
-
-        synchronized (mLock) {
-            if (mGnssBatchingProvider != null) {
-                mGnssBatchingInProgress = false;
-                return mGnssBatchingProvider.stop();
-            } else {
-                return false;
-            }
-        }
+        return mGnssManagerService == null ? false : mGnssManagerService.stopGnssBatch();
     }
 
     @GuardedBy("mLock")
@@ -2191,7 +1993,7 @@
     }
 
     @GuardedBy("mLock")
-    private boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
+    public boolean isThrottlingExemptLocked(CallerIdentity callerIdentity) {
         if (callerIdentity.mUid == Process.SYSTEM_UID) {
             return true;
         }
@@ -2236,8 +2038,10 @@
             mRealRequest = request;
             mRequest = request;
             mReceiver = receiver;
-            mIsForegroundUid = isImportanceForeground(
-                    mActivityManager.getPackageImportance(mReceiver.mCallerIdentity.mPackageName));
+            mIsForegroundUid =
+                    LocationManagerServiceUtils.isImportanceForeground(
+                            mActivityManager.getPackageImportance(
+                                    mReceiver.mCallerIdentity.mPackageName));
 
             if (D && receiver.mCallerIdentity.mPid == Process.myPid()) {
                 mStackTrace = new Throwable();
@@ -2335,8 +2139,8 @@
         if (receiver == null) {
             receiver = new Receiver(listener, null, pid, uid, packageName, workSource,
                     hideFromAppOps);
-            if (!linkToListenerDeathNotificationLocked(receiver.getListener().asBinder(),
-                    receiver)) {
+            if (!receiver.linkToListenerDeathNotificationLocked(
+                    receiver.getListener().asBinder())) {
                 return null;
             }
             mReceivers.put(binder, receiver);
@@ -2558,8 +2362,8 @@
         if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
 
         if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
-            unlinkFromListenerDeathNotificationLocked(receiver.getListener().asBinder(),
-                    receiver);
+            receiver.unlinkFromListenerDeathNotificationLocked(
+                    receiver.getListener().asBinder());
             receiver.clearPendingBroadcastsLocked();
         }
 
@@ -2606,7 +2410,6 @@
                     return null;
                 }
 
-
                 // Figure out the provider. Either its explicitly request (deprecated API's),
                 // or use the fused provider
                 String name = request.getProvider();
@@ -2666,7 +2469,7 @@
                         if (D) {
                             Log.d(TAG, "not returning last loc for no op app: " + packageName);
                         }
-                        lastLocation =  null;
+                        lastLocation = null;
                     }
                 }
                 return lastLocation;
@@ -2696,13 +2499,6 @@
         mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                 "Access Fine Location permission not granted to inject Location");
 
-        if (location == null) {
-            if (D) {
-                Log.d(TAG, "injectLocation(): called with null location");
-            }
-            return false;
-        }
-
         synchronized (mLock) {
             LocationProvider provider = getLocationProviderLocked(location.getProvider());
             if (provider == null || !provider.isUseableLocked()) {
@@ -2807,219 +2603,58 @@
 
     @Override
     public boolean registerGnssStatusCallback(IGnssStatusListener listener, String packageName) {
-        return addGnssDataListener(listener, packageName, "GnssStatusListener",
-                mGnssStatusProvider, mGnssStatusListeners,
-                this::unregisterGnssStatusCallback);
+        return mGnssManagerService == null ? false : mGnssManagerService.registerGnssStatusCallback(
+                listener, packageName);
     }
 
     @Override
     public void unregisterGnssStatusCallback(IGnssStatusListener listener) {
-        removeGnssDataListener(listener, mGnssStatusProvider, mGnssStatusListeners);
+        if (mGnssManagerService != null) mGnssManagerService.unregisterGnssStatusCallback(listener);
     }
 
     @Override
     public boolean addGnssMeasurementsListener(
             IGnssMeasurementsListener listener, String packageName) {
-        return addGnssDataListener(listener, packageName, "GnssMeasurementsListener",
-                mGnssMeasurementsProvider, mGnssMeasurementsListeners,
-                this::removeGnssMeasurementsListener);
+        return mGnssManagerService == null ? false
+                : mGnssManagerService.addGnssMeasurementsListener(listener, packageName);
     }
 
     @Override
     public void removeGnssMeasurementsListener(IGnssMeasurementsListener listener) {
-        removeGnssDataListener(listener, mGnssMeasurementsProvider, mGnssMeasurementsListeners);
-    }
-
-    private abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
-        protected final CallerIdentity mCallerIdentity;
-        protected final String mListenerName;
-
-        private LinkedListenerBase(@NonNull CallerIdentity callerIdentity,
-                @NonNull String listenerName) {
-            mCallerIdentity = callerIdentity;
-            mListenerName = listenerName;
-        }
-
-        @Override
-        public String toString() {
-            return mListenerName + "[" + mCallerIdentity.mPackageName + "(" + mCallerIdentity.mPid
-                    + ")]";
-        }
-    }
-
-    private static class LinkedListener<TListener> extends LinkedListenerBase {
-        private final TListener mListener;
-        private final Consumer<TListener> mBinderDeathCallback;
-
-        private LinkedListener(@NonNull TListener listener, String listenerName,
-                @NonNull CallerIdentity callerIdentity,
-                @NonNull Consumer<TListener> binderDeathCallback) {
-            super(callerIdentity, listenerName);
-            mListener = listener;
-            mBinderDeathCallback = binderDeathCallback;
-        }
-
-        @Override
-        public void binderDied() {
-            if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
-            mBinderDeathCallback.accept(mListener);
-        }
-    }
-
-    private <TListener extends IInterface> boolean addGnssDataListener(
-            TListener listener, String packageName, String listenerName,
-            RemoteListenerHelper<TListener> gnssDataProvider,
-            ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners,
-            Consumer<TListener> binderDeathCallback) {
-        if (!hasGnssPermissions(packageName) || gnssDataProvider == null) {
-            return false;
-        }
-
-        CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
-                Binder.getCallingPid(), packageName);
-        LinkedListener<TListener> linkedListener = new LinkedListener<>(listener,
-                listenerName, callerIdentity, binderDeathCallback);
-        IBinder binder = listener.asBinder();
-        synchronized (mLock) {
-            if (!linkToListenerDeathNotificationLocked(binder, linkedListener)) {
-                return false;
-            }
-
-            gnssDataListeners.put(binder, linkedListener);
-            long identity = Binder.clearCallingIdentity();
-            try {
-                if (gnssDataProvider == mGnssMeasurementsProvider
-                        || gnssDataProvider == mGnssStatusProvider) {
-                    mLocationUsageLogger.logLocationApiUsage(
-                            LocationStatsEnums.USAGE_STARTED,
-                            gnssDataProvider == mGnssMeasurementsProvider
-                                ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
-                                : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
-                            packageName,
-                            /* LocationRequest= */ null,
-                            /* hasListener= */ true,
-                            /* hasIntent= */ false,
-                            /* geofence= */ null,
-                            mActivityManager.getPackageImportance(packageName));
-                }
-                if (isThrottlingExemptLocked(callerIdentity)
-                        || isImportanceForeground(
-                        mActivityManager.getPackageImportance(packageName))) {
-                    gnssDataProvider.addListener(listener, callerIdentity);
-                }
-                return true;
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    private <TListener extends IInterface> void removeGnssDataListener(
-            TListener listener, RemoteListenerHelper<TListener> gnssDataProvider,
-            ArrayMap<IBinder, LinkedListener<TListener>> gnssDataListeners) {
-        if (gnssDataProvider == null) {
-            return;
-        }
-
-        IBinder binder = listener.asBinder();
-        synchronized (mLock) {
-            LinkedListener<TListener> linkedListener = gnssDataListeners.remove(binder);
-            if (linkedListener == null) {
-                return;
-            }
-            long identity = Binder.clearCallingIdentity();
-            try {
-                if (gnssDataProvider == mGnssMeasurementsProvider
-                        || gnssDataProvider == mGnssStatusProvider) {
-                    mLocationUsageLogger.logLocationApiUsage(
-                            LocationStatsEnums.USAGE_ENDED,
-                            gnssDataProvider == mGnssMeasurementsProvider
-                                ? LocationStatsEnums.API_ADD_GNSS_MEASUREMENTS_LISTENER
-                                : LocationStatsEnums.API_REGISTER_GNSS_STATUS_CALLBACK,
-                            linkedListener.mCallerIdentity.mPackageName,
-                            /* LocationRequest= */ null,
-                            /* hasListener= */ true,
-                            /* hasIntent= */ false,
-                            /* geofence= */ null,
-                            mActivityManager.getPackageImportance(
-                                    linkedListener.mCallerIdentity.mPackageName));
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-            unlinkFromListenerDeathNotificationLocked(binder, linkedListener);
-            gnssDataProvider.removeListener(listener);
-        }
-    }
-
-    private boolean linkToListenerDeathNotificationLocked(IBinder binder,
-            LinkedListenerBase linkedListener) {
-        try {
-            binder.linkToDeath(linkedListener, 0 /* flags */);
-            return true;
-        } catch (RemoteException e) {
-            // if the remote process registering the listener is already dead, just swallow the
-            // exception and return
-            Log.w(TAG, "Could not link " + linkedListener.mListenerName + " death callback.", e);
-            return false;
-        }
-    }
-
-    private boolean unlinkFromListenerDeathNotificationLocked(IBinder binder,
-            LinkedListenerBase linkedListener) {
-        try {
-            binder.unlinkToDeath(linkedListener, 0 /* flags */);
-            return true;
-        } catch (NoSuchElementException e) {
-            // if the death callback isn't connected (it should be...), log error,
-            // swallow the exception and return
-            Log.w(TAG, "Could not unlink " + linkedListener.mListenerName + " death callback.", e);
-            return false;
+        if (mGnssManagerService != null) {
+            mGnssManagerService.removeGnssMeasurementsListener(
+                    listener);
         }
     }
 
     @Override
     public void injectGnssMeasurementCorrections(
             GnssMeasurementCorrections measurementCorrections, String packageName) {
-        mContext.enforceCallingPermission(
-                android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to inject GNSS measurement corrections.");
-        if (!hasGnssPermissions(packageName)) {
-            Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
-            return;
+        if (mGnssManagerService != null) {
+            mGnssManagerService.injectGnssMeasurementCorrections(
+                    measurementCorrections, packageName);
         }
-        if (mGnssMeasurementCorrectionsProvider == null) {
-            Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider "
-                    + "not available.");
-            return;
-        }
-        mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
-                measurementCorrections);
     }
 
     @Override
     public long getGnssCapabilities(String packageName) {
-        mContext.enforceCallingPermission(
-                android.Manifest.permission.LOCATION_HARDWARE,
-                "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
-        if (!hasGnssPermissions(packageName) || mGnssCapabilitiesProvider == null) {
-            return GnssCapabilities.INVALID_CAPABILITIES;
-        }
-        return mGnssCapabilitiesProvider.getGnssCapabilities();
+        return mGnssManagerService == null ? 0L : mGnssManagerService.getGnssCapabilities(
+                packageName);
     }
 
     @Override
     public boolean addGnssNavigationMessageListener(
             IGnssNavigationMessageListener listener, String packageName) {
-        return addGnssDataListener(listener, packageName, "GnssNavigationMessageListener",
-                mGnssNavigationMessageProvider, mGnssNavigationMessageListeners,
-                this::removeGnssNavigationMessageListener);
+        return mGnssManagerService == null ? false
+                : mGnssManagerService.addGnssNavigationMessageListener(listener, packageName);
     }
 
     @Override
     public void removeGnssNavigationMessageListener(IGnssNavigationMessageListener listener) {
-        removeGnssDataListener(listener, mGnssNavigationMessageProvider,
-                mGnssNavigationMessageListeners);
+        if (mGnssManagerService != null) {
+            mGnssManagerService.removeGnssNavigationMessageListener(
+                    listener);
+        }
     }
 
     @Override
@@ -3059,24 +2694,13 @@
 
     @Override
     public boolean sendNiResponse(int notifId, int userResponse) {
-        if (Binder.getCallingUid() != Process.myUid()) {
-            throw new SecurityException(
-                    "calling sendNiResponse from outside of the system is not allowed");
-        }
-        try {
-            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
-            return false;
-        }
+        return mGnssManagerService == null ? false : mGnssManagerService.sendNiResponse(notifId,
+                userResponse);
     }
 
     @Override
     public ProviderProperties getProviderProperties(String providerName) {
         synchronized (mLock) {
-            checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
-                    providerName);
-
             LocationProvider provider = getLocationProviderLocked(providerName);
             if (provider == null) {
                 return null;
@@ -3149,10 +2773,10 @@
         long identity = Binder.clearCallingIdentity();
         try {
             return Settings.Secure.getIntForUser(
-                        mContext.getContentResolver(),
-                        Settings.Secure.LOCATION_MODE,
-                        Settings.Secure.LOCATION_MODE_OFF,
-                        userId) != Settings.Secure.LOCATION_MODE_OFF;
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCATION_MODE,
+                    Settings.Secure.LOCATION_MODE_OFF,
+                    userId) != Settings.Secure.LOCATION_MODE_OFF;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -3566,11 +3190,8 @@
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
 
         synchronized (mLock) {
-            if (args.length > 0 && args[0].equals("--gnssmetrics")) {
-                if (mGnssMetricsProvider != null) {
-                    pw.append(mGnssMetricsProvider.getGnssMetricsAsProtoString());
-                }
-                return;
+            if (mGnssManagerService != null && args.length > 0 && args[0].equals("--gnssmetrics")) {
+                mGnssManagerService.dump(fd, pw, args);
             }
 
             ipw.println("Location Manager State:");
@@ -3604,27 +3225,6 @@
             }
             ipw.decreaseIndent();
 
-            ipw.println("GnssMeasurement Listeners:");
-            ipw.increaseIndent();
-            for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
-                ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
-            }
-            ipw.decreaseIndent();
-
-            ipw.println("GnssNavigationMessage Listeners:");
-            ipw.increaseIndent();
-            for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
-                ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
-            }
-            ipw.decreaseIndent();
-
-            ipw.println("GnssStatus Listeners:");
-            ipw.increaseIndent();
-            for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
-                ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
-            }
-            ipw.decreaseIndent();
-
             ipw.println("Historical Records by Provider:");
             ipw.increaseIndent();
             for (Map.Entry<PackageProviderKey, PackageStatistics> entry
@@ -3654,7 +3254,7 @@
                 mGeofenceManager.dump(ipw);
                 ipw.decreaseIndent();
             }
-          
+
             if (mBlacklist != null) {
                 mBlacklist.dump(ipw);
             }
@@ -3694,11 +3294,11 @@
             for (LocationProvider provider : mProviders) {
                 provider.dumpLocked(fd, ipw, args);
             }
-            ipw.decreaseIndent();
+        }
 
-            if (mGnssBatchingInProgress) {
-                ipw.println("GNSS batching in progress");
-            }
+        if (mGnssManagerService != null) {
+            ipw.decreaseIndent();
+            mGnssManagerService.dump(fd, pw, args);
         }
     }
 }
diff --git a/services/core/java/com/android/server/LocationManagerServiceUtils.java b/services/core/java/com/android/server/LocationManagerServiceUtils.java
new file mode 100644
index 0000000..9c8ac19
--- /dev/null
+++ b/services/core/java/com/android/server/LocationManagerServiceUtils.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.server.location.CallerIdentity;
+
+import java.util.NoSuchElementException;
+import java.util.function.Consumer;
+
+/**
+ * Shared utilities for LocationManagerService and GnssManager.
+ */
+public class LocationManagerServiceUtils {
+
+    private static final String TAG = "LocManagerServiceUtils";
+    private static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * Listener that can be linked to a binder.
+     * @param <TListener> listener type
+     */
+    public static class LinkedListener<TListener> extends
+            LinkedListenerBase {
+        private final TListener mListener;
+        private final Consumer<TListener> mBinderDeathCallback;
+
+        public LinkedListener(
+                @NonNull TListener listener,
+                String listenerName,
+                @NonNull CallerIdentity callerIdentity,
+                @NonNull Consumer<TListener> binderDeathCallback) {
+            super(callerIdentity, listenerName);
+            mListener = listener;
+            mBinderDeathCallback = binderDeathCallback;
+        }
+
+        @Override
+        public void binderDied() {
+            if (D) Log.d(TAG, "Remote " + mListenerName + " died.");
+            mBinderDeathCallback.accept(mListener);
+        }
+    }
+
+    /**
+     * Skeleton class of listener that can be linked to a binder.
+     */
+    public abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
+        protected final CallerIdentity mCallerIdentity;
+        protected final String mListenerName;
+
+        LinkedListenerBase(
+                @NonNull CallerIdentity callerIdentity, @NonNull String listenerName) {
+            mCallerIdentity = callerIdentity;
+            mListenerName = listenerName;
+        }
+
+        @Override
+        public String toString() {
+            return mListenerName + "[" + mCallerIdentity.mPackageName + "(" + mCallerIdentity.mPid
+                    + ")]";
+        }
+
+        public CallerIdentity getCallerIdentity() {
+            return mCallerIdentity;
+        }
+
+        public String getListenerName() {
+            return mListenerName;
+        }
+
+        /**
+         * Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
+         *
+         * @param binder that calls listener upon death
+         * @return true if listener is successfully linked to binder, false otherwise
+         */
+        public boolean linkToListenerDeathNotificationLocked(
+                IBinder binder) {
+            try {
+                binder.linkToDeath(this, 0 /* flags */);
+                return true;
+            } catch (RemoteException e) {
+                // if the remote process registering the listener is already dead, just swallow the
+                // exception and return
+                Log.w(TAG, "Could not link " + mListenerName + " death callback.", e);
+                return false;
+            }
+        }
+
+        /**
+         * Unlink death listener (i.e. callback) from binder.
+         *
+         * @param binder that calls listener upon death
+         * @return true if binder is successfully unlinked from binder, false otherwise
+         */
+        public boolean unlinkFromListenerDeathNotificationLocked(
+                IBinder binder) {
+            try {
+                binder.unlinkToDeath(this, 0 /* flags */);
+                return true;
+            } catch (NoSuchElementException e) {
+                // if the death callback isn't connected (it should be...), log error,
+                // swallow the exception and return
+                Log.w(TAG, "Could not unlink " + mListenerName + " death callback.", e);
+                return false;
+            }
+        }
+
+    }
+
+    /**
+     * Convert boolean foreground into "foreground" or "background" string.
+     *
+     * @param foreground boolean indicating foreground
+     * @return "foreground" string if true, false otherwise
+     */
+    public static String foregroundAsString(boolean foreground) {
+        return foreground ? "foreground" : "background";
+    }
+
+
+    /**
+     * Classifies importance level as foreground or not.
+     *
+     * @param importance level as int
+     * @return boolean indicating if importance level is foreground or greater
+     */
+    public static boolean isImportanceForeground(int importance) {
+        return importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+    }
+
+    /**
+     * Get package importance level.
+     *
+     * @param packageName package name
+     * @return package importance level as int
+     */
+    public static int getPackageImportance(String packageName, Context context) {
+        return ((ActivityManager) context.getSystemService(
+                Context.ACTIVITY_SERVICE)).getPackageImportance(packageName);
+    }
+}
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index fa1653d..793e342 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -88,7 +88,7 @@
             }
         };
 
-        if (mWipeExternalStorage || mWipeEsims) {
+        if (mWipeExternalStorage) {
             // thr will be started at the end of this task.
             new WipeDataTask(context, thr).execute();
         } else {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f70d511..3916f0d 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -197,7 +197,7 @@
             "persist.sys.zram_enabled";
 
     private static final boolean IS_FUSE_ENABLED =
-            SystemProperties.getBoolean("persist.sys.fuse", false);
+            SystemProperties.getBoolean(StorageManager.PROP_FUSE, false);
 
     private static final boolean ENABLE_ISOLATED_STORAGE = StorageManager.hasIsolatedStorage();
 
@@ -208,6 +208,12 @@
      */
     private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
 
+    /**
+     * If {@code 1}, enables FuseDaemon to intercept file system ops. If {@code -1},
+     * disables FuseDaemon. If {@code 0}, uses the default value from the build system.
+     */
+    private static final String FUSE_ENABLED = "fuse_enabled";
+
     public static class Lifecycle extends SystemService {
         private StorageManagerService mStorageManagerService;
 
@@ -814,11 +820,13 @@
                 }
             });
         // For now, simply clone property when it changes
-        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE,
+        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
                 mContext.getMainExecutor(), (properties) -> {
                     refreshIsolatedStorageSettings();
+                    refreshFuseSettings();
                 });
         refreshIsolatedStorageSettings();
+        refreshFuseSettings();
     }
 
     /**
@@ -854,7 +862,8 @@
         // Always copy value from newer DeviceConfig location
         Settings.Global.putString(mResolver,
                 Settings.Global.ISOLATED_STORAGE_REMOTE,
-                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE, ISOLATED_STORAGE_ENABLED));
+                DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                        ISOLATED_STORAGE_ENABLED));
 
         final int local = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
@@ -881,6 +890,18 @@
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
     }
 
+    private void refreshFuseSettings() {
+        int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                FUSE_ENABLED, 0);
+        if (isFuseEnabled == 1) {
+            SystemProperties.set(StorageManager.PROP_FUSE, "true");
+        } else if (isFuseEnabled == -1) {
+            SystemProperties.set(StorageManager.PROP_FUSE, "false");
+        }
+        // else, keep the build config.
+        // This can be overridden be direct adjustment of persist.sys.prop
+    }
+
     /**
      * MediaProvider has a ton of code that makes assumptions about storage
      * paths never changing, so we outright kill them to pick up new state.
@@ -1526,6 +1547,9 @@
         SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
                 SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
 
+        SystemProperties.set(StorageManager.PROP_FUSE_SNAPSHOT, Boolean.toString(
+                SystemProperties.getBoolean(StorageManager.PROP_FUSE, false)));
+
         mContext = context;
         mResolver = mContext.getContentResolver();
 
@@ -1858,7 +1882,7 @@
             // This means the mountUserId on such volumes is USER_NULL. This breaks fuse which
             // requires a valid user to mount a volume. Create individual volumes per user in vold
             // and remove this property check
-            int userId = SystemProperties.getBoolean("persist.sys.fuse", false)
+            int userId = SystemProperties.getBoolean(StorageManager.PROP_FUSE_SNAPSHOT, false)
                     ? mCurrentUserId : vol.mountUserId;
             return mVold.mount(vol.id, vol.mountFlags, userId);
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c412ebd..f91cf0c 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -33,6 +33,9 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SrvccState;
 import android.telephony.CallAttributes;
 import android.telephony.CallQuality;
 import android.telephony.CellInfo;
@@ -208,6 +211,10 @@
 
     private Map<Integer, List<EmergencyNumber>> mEmergencyNumberList;
 
+    private EmergencyNumber[] mOutgoingSmsEmergencyNumber;
+
+    private EmergencyNumber[] mOutgoingCallEmergencyNumber;
+
     private CallQuality[] mCallQuality;
 
     private CallAttributes[] mCallAttributes;
@@ -241,7 +248,7 @@
 
     private int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
-    @TelephonyManager.RadioPowerState
+    @RadioPowerState
     private int mRadioPowerState = TelephonyManager.RADIO_POWER_UNAVAILABLE;
 
     private final LocalLog mLocalLog = new LocalLog(100);
@@ -266,6 +273,10 @@
                 PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
                 PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
 
+    static final int READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK =
+            PhoneStateListener.LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER
+                    | PhoneStateListener.LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER;
+
     private static final int MSG_USER_SWITCHED = 1;
     private static final int MSG_UPDATE_DEFAULT_SUB = 2;
 
@@ -374,7 +385,7 @@
         mContext = context;
         mBatteryStats = BatteryStatsService.getService();
 
-        int numPhones = TelephonyManager.getDefault().getPhoneCount();
+        int numPhones = TelephonyManager.getDefault().getMaxPhoneCount();
         if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones);
         mNumPhones = numPhones;
         mCallState = new int[numPhones];
@@ -406,6 +417,8 @@
         mImsReasonInfo = new ArrayList<>();
         mPhysicalChannelConfigs = new ArrayList<>();
         mEmergencyNumberList = new HashMap<>();
+        mOutgoingCallEmergencyNumber = new EmergencyNumber[numPhones];
+        mOutgoingSmsEmergencyNumber = new EmergencyNumber[numPhones];
         for (int i = 0; i < numPhones; i++) {
             mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
             mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
@@ -1193,7 +1206,7 @@
     public void notifyCarrierNetworkChange(boolean active) {
         // only CarrierService with carrier privilege rule should have the permission
         int[] subIds = Arrays.stream(SubscriptionManager.from(mContext)
-                    .getActiveSubscriptionIdList())
+                    .getActiveSubscriptionIdList(false))
                     .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray();
         if (ArrayUtils.isEmpty(subIds)) {
             loge("notifyCarrierNetworkChange without carrier privilege");
@@ -1708,7 +1721,7 @@
     }
 
     public void notifyPreciseDataConnectionFailed(int phoneId, int subId, String apnType,
-            String apn, @DataFailCause.FailCause int failCause) {
+            String apn, @DataFailureCause int failCause) {
         if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
             return;
         }
@@ -1738,7 +1751,7 @@
     }
 
     @Override
-    public void notifySrvccStateChanged(int subId, @TelephonyManager.SrvccState int state) {
+    public void notifySrvccStateChanged(int subId, @SrvccState int state) {
         if (!checkNotifyPermission("notifySrvccStateChanged()")) {
             return;
         }
@@ -1845,8 +1858,7 @@
         }
     }
 
-    public void notifyRadioPowerStateChanged(int phoneId, int subId,
-                                             @TelephonyManager.RadioPowerState int state) {
+    public void notifyRadioPowerStateChanged(int phoneId, int subId, @RadioPowerState int state) {
         if (!checkNotifyPermission("notifyRadioPowerStateChanged()")) {
             return;
         }
@@ -1910,6 +1922,56 @@
     }
 
     @Override
+    public void notifyOutgoingEmergencyCall(int phoneId, int subId,
+            EmergencyNumber emergencyNumber) {
+        if (!checkNotifyPermission("notifyOutgoingEmergencyCall()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                mOutgoingCallEmergencyNumber[phoneId] = emergencyNumber;
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER)
+                                    && idMatch(r.subId, subId, phoneId)) {
+                        try {
+                            r.callback.onOutgoingEmergencyCall(emergencyNumber);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
+    @Override
+    public void notifyOutgoingEmergencySms(int phoneId, int subId,
+            EmergencyNumber emergencyNumber) {
+        if (!checkNotifyPermission("notifyOutgoingEmergencySms()")) {
+            return;
+        }
+        synchronized (mRecords) {
+            if (validatePhoneId(phoneId)) {
+                mOutgoingSmsEmergencyNumber[phoneId] = emergencyNumber;
+                for (Record r : mRecords) {
+                    if (r.matchPhoneStateListenerEvent(
+                            PhoneStateListener.LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER)
+                                    && idMatch(r.subId, subId, phoneId)) {
+                        try {
+                            r.callback.onOutgoingEmergencySms(emergencyNumber);
+                        } catch (RemoteException ex) {
+                            mRemoveList.add(r.binder);
+                        }
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
+    @Override
     public void notifyCallQualityChanged(CallQuality callQuality, int phoneId, int subId,
             int callNetworkType) {
         if (!checkNotifyPermission("notifyCallQualityChanged()")) {
@@ -1981,6 +2043,8 @@
                 pw.println("mCallAttributes=" + mCallAttributes[i]);
                 pw.println("mCallNetworkType=" + mCallNetworkType[i]);
                 pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState[i]);
+                pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]);
+                pw.println("mOutgoingSmsEmergencyNumber=" + mOutgoingSmsEmergencyNumber[i]);
                 pw.decreaseIndent();
             }
             pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
@@ -2165,7 +2229,7 @@
 
     private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
             String apnType, String apn, LinkProperties linkProperties,
-            @DataFailCause.FailCause int failCause) {
+            @DataFailureCause int failCause) {
         Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
         intent.putExtra(PhoneConstants.STATE_KEY, state);
         intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
@@ -2250,6 +2314,11 @@
                     android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
         }
 
+        if ((events & READ_ACTIVE_EMERGENCY_SESSION_PERMISSION_MASK) != 0) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
+        }
+
         if ((events & PhoneStateListener.LISTEN_OEM_HOOK_RAW_EVENT) != 0) {
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
diff --git a/services/core/java/com/android/server/UiThread.java b/services/core/java/com/android/server/UiThread.java
index b2fa684..34fc9ab 100644
--- a/services/core/java/com/android/server/UiThread.java
+++ b/services/core/java/com/android/server/UiThread.java
@@ -21,6 +21,8 @@
 import android.os.Process;
 import android.os.Trace;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Shared singleton thread for showing UI.  This is a foreground thread, and in
  * additional should not have operations that can take more than a few ms scheduled
@@ -68,4 +70,20 @@
             return sHandler;
         }
     }
+
+    /**
+     * Disposes current ui thread if it's initialized. Should only be used in tests to set up a
+     * new environment.
+     */
+    @VisibleForTesting
+    public static void dispose() {
+        synchronized (UiThread.class) {
+            if (sInstance == null) {
+                return;
+            }
+
+            getHandler().runWithScissors(sInstance::quit, 0 /* timeout */);
+            sInstance = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 9936d73..d622fb4 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -29,6 +29,7 @@
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
 import android.hardware.vibrator.V1_0.EffectStrength;
+import android.hardware.vibrator.V1_4.Capabilities;
 import android.icu.text.DateFormat;
 import android.media.AudioAttributes;
 import android.media.AudioManager;
@@ -108,6 +109,9 @@
     // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
     private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
 
+    // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
+    private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
+
 
     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
     // adjustment is defined as the delta between the default intensity level and the user selected
@@ -123,6 +127,7 @@
     private final boolean mAllowPriorityVibrationsInLowPowerMode;
     private final boolean mSupportsAmplitudeControl;
     private final boolean mSupportsExternalControl;
+    private final long mCapabilities;
     private final int mDefaultVibrationAmplitude;
     private final SparseArray<VibrationEffect> mFallbackEffects;
     private final SparseArray<Integer> mProcStatesCache = new SparseArray();
@@ -163,9 +168,10 @@
     static native void vibratorOff();
     static native boolean vibratorSupportsAmplitudeControl();
     static native void vibratorSetAmplitude(int amplitude);
-    static native long vibratorPerformEffect(long effect, long strength);
+    static native long vibratorPerformEffect(long effect, long strength, Vibration vibration);
     static native boolean vibratorSupportsExternalControl();
     static native void vibratorSetExternalControl(boolean enabled);
+    static native long vibratorGetCapabilities();
 
     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
@@ -226,6 +232,14 @@
             }
         }
 
+        private void onComplete() {
+            synchronized (mLock) {
+                if (this == mCurrentVibration) {
+                    doCancelVibrateLocked();
+                }
+            }
+        }
+
         public boolean hasTimeoutLongerThan(long millis) {
             final long duration = effect.getDuration();
             return duration >= 0 && duration > millis;
@@ -347,6 +361,7 @@
 
         mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
         mSupportsExternalControl = vibratorSupportsExternalControl();
+        mCapabilities = vibratorGetCapabilities();
 
         mContext = context;
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -1135,10 +1150,14 @@
             }
             // Input devices don't support prebaked effect, so skip trying it with them.
             if (!usingInputDeviceVibrators) {
-                long timeout = vibratorPerformEffect(prebaked.getId(),
-                        prebaked.getEffectStrength());
+                long duration = vibratorPerformEffect(prebaked.getId(),
+                        prebaked.getEffectStrength(), vib);
+                long timeout = duration;
+                if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) {
+                    timeout *= ASYNC_TIMEOUT_MULTIPLIER;
+                }
                 if (timeout > 0) {
-                    noteVibratorOnLocked(vib.uid, timeout);
+                    noteVibratorOnLocked(vib.uid, duration);
                     return timeout;
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7b69bea..ee98af4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -233,6 +233,7 @@
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.BinderProxy;
+import android.os.BugreportParams;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
@@ -2404,7 +2405,8 @@
         final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
         mProcessList.init(this, activeUids);
         mLowMemDetector = null;
-        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
+        mOomAdjuster = hasHandlerThread
+                ? new OomAdjuster(this, mProcessList, activeUids, handlerThread) : null;
 
         mIntentFirewall = hasHandlerThread
                 ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
@@ -7439,6 +7441,7 @@
                         dst.setProcess(r);
                         dst.notifyAll();
                     }
+                    dst.mRestartCount = 0;
                     updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                     maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                             src.info.authority);
@@ -8255,22 +8258,22 @@
             @Nullable String shareDescription, int bugreportType) {
         String type = null;
         switch (bugreportType) {
-            case ActivityManager.BUGREPORT_OPTION_FULL:
+            case BugreportParams.BUGREPORT_MODE_FULL:
                 type = "bugreportfull";
                 break;
-            case ActivityManager.BUGREPORT_OPTION_INTERACTIVE:
+            case BugreportParams.BUGREPORT_MODE_INTERACTIVE:
                 type = "bugreportplus";
                 break;
-            case ActivityManager.BUGREPORT_OPTION_REMOTE:
+            case BugreportParams.BUGREPORT_MODE_REMOTE:
                 type = "bugreportremote";
                 break;
-            case ActivityManager.BUGREPORT_OPTION_WEAR:
+            case BugreportParams.BUGREPORT_MODE_WEAR:
                 type = "bugreportwear";
                 break;
-            case ActivityManager.BUGREPORT_OPTION_TELEPHONY:
+            case BugreportParams.BUGREPORT_MODE_TELEPHONY:
                 type = "bugreporttelephony";
                 break;
-            case ActivityManager.BUGREPORT_OPTION_WIFI:
+            case BugreportParams.BUGREPORT_MODE_WIFI:
                 type = "bugreportwifi";
                 break;
             default:
@@ -8305,7 +8308,7 @@
         final boolean useApi = FeatureFlagUtils.isEnabled(mContext,
                 FeatureFlagUtils.USE_BUGREPORT_API);
 
-        if (useApi && bugreportType == ActivityManager.BUGREPORT_OPTION_INTERACTIVE) {
+        if (useApi) {
             // Create intent to trigger Bugreport API via Shell
             Intent triggerShellBugreport = new Intent();
             triggerShellBugreport.setAction(INTENT_BUGREPORT_REQUESTED);
@@ -8341,7 +8344,7 @@
     @Override
     public void requestTelephonyBugReport(String shareTitle, String shareDescription) {
         requestBugReportWithDescription(shareTitle, shareDescription,
-                ActivityManager.BUGREPORT_OPTION_TELEPHONY);
+                BugreportParams.BUGREPORT_MODE_TELEPHONY);
     }
 
     /**
@@ -8353,7 +8356,7 @@
     @Override
     public void requestWifiBugReport(String shareTitle, String shareDescription) {
         requestBugReportWithDescription(shareTitle, shareDescription,
-                ActivityManager.BUGREPORT_OPTION_WIFI);
+                BugreportParams.BUGREPORT_MODE_WIFI);
     }
 
     /**
@@ -8361,7 +8364,7 @@
      */
     @Override
     public void requestInteractiveBugReport() {
-        requestBugReportWithDescription(null, null, ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+        requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_INTERACTIVE);
     }
 
     /**
@@ -8372,7 +8375,7 @@
     public void requestInteractiveBugReportWithDescription(String shareTitle,
             String shareDescription) {
         requestBugReportWithDescription(shareTitle, shareDescription,
-                ActivityManager.BUGREPORT_OPTION_INTERACTIVE);
+                BugreportParams.BUGREPORT_MODE_INTERACTIVE);
     }
 
     /**
@@ -8380,7 +8383,7 @@
      */
     @Override
     public void requestFullBugReport() {
-        requestBugReportWithDescription(null, null, ActivityManager.BUGREPORT_OPTION_FULL);
+        requestBugReportWithDescription(null, null,  BugreportParams.BUGREPORT_MODE_FULL);
     }
 
     /**
@@ -8388,7 +8391,7 @@
      */
     @Override
     public void requestRemoteBugReport() {
-        requestBugReportWithDescription(null, null, ActivityManager.BUGREPORT_OPTION_REMOTE);
+        requestBugReportWithDescription(null, null, BugreportParams.BUGREPORT_MODE_REMOTE);
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -13882,9 +13885,20 @@
         return false;
     }
 
+    /**
+     * Remove the dying provider from known provider map and launching provider map.
+     * @param proc The dying process recoder
+     * @param cpr The provider to be removed.
+     * @param always If true, remove the provider from launching map always, no more restart attempt
+     * @return true if the given provider is in launching
+     */
     private final boolean removeDyingProviderLocked(ProcessRecord proc,
             ContentProviderRecord cpr, boolean always) {
-        final boolean inLaunching = mLaunchingProviders.contains(cpr);
+        boolean inLaunching = mLaunchingProviders.contains(cpr);
+        if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
+            // It's being launched but we've reached maximum attempts, force the removal
+            always = true;
+        }
 
         if (!inLaunching || always) {
             synchronized (cpr) {
@@ -13936,6 +13950,8 @@
 
         if (inLaunching && always) {
             mLaunchingProviders.remove(cpr);
+            cpr.mRestartCount = 0;
+            inLaunching = false;
         }
         return inLaunching;
     }
@@ -14151,6 +14167,10 @@
         for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
             ContentProviderRecord cpr = mLaunchingProviders.get(i);
             if (cpr.launchingApp == app) {
+                if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
+                    // It's being launched but we've reached maximum attempts, mark it as bad
+                    alwaysBad = true;
+                }
                 if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
                     restart = true;
                 } else {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 058afd3..8be2438 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2859,7 +2859,21 @@
         return 0;
     }
 
-    private int runCompat(PrintWriter pw) {
+    private void killPackage(String packageName, PrintWriter pw) throws RemoteException {
+        int uid = mPm.getPackageUid(packageName, 0, mUserId);
+        if (uid < 0) {
+            // uid is negative if the package wasn't found.
+            pw.println("Didn't find package " + packageName + " on device.");
+        } else {
+            pw.println("Killing package " + packageName + " (UID " + uid + ").");
+            final long origId = Binder.clearCallingIdentity();
+            mInterface.killUid(UserHandle.getAppId(uid),
+                    UserHandle.USER_ALL, "killPackage");
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    private int runCompat(PrintWriter pw) throws RemoteException {
         final CompatConfig config = CompatConfig.get();
         String toggleValue = getNextArgRequired();
         long changeId;
@@ -2873,13 +2887,14 @@
             pw.println("Unknown or invalid change: '" + changeIdString + "'.");
         }
         String packageName = getNextArgRequired();
-        switch(toggleValue) {
+        switch (toggleValue) {
             case "enable":
                 if (!config.addOverride(changeId, packageName, true)) {
                     pw.println("Warning! Change " + changeId + " is not known yet. Enabling it"
                             + " could have no effect.");
                 }
                 pw.println("Enabled change " + changeId + " for " + packageName + ".");
+                killPackage(packageName, pw);
                 return 0;
             case "disable":
                 if (!config.addOverride(changeId, packageName, false)) {
@@ -2887,11 +2902,13 @@
                             + " could have no effect.");
                 }
                 pw.println("Disabled change " + changeId + " for " + packageName + ".");
+                killPackage(packageName, pw);
                 return 0;
             case "reset":
                 if (config.removeOverride(changeId, packageName)) {
                     pw.println("Reset change " + changeId + " for " + packageName
                             + " to default value.");
+                    killPackage(packageName, pw);
                 } else {
                     pw.println("No override exists for changeId " + changeId + ".");
                 }
@@ -3210,6 +3227,7 @@
             pw.println("      Write all pending state to storage.");
             pw.println("  compat enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
             pw.println("      Toggles a change either by id or by name for <PACKAGE_NAME>.");
+            pw.println("      It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
             pw.println();
             Intent.printIntentArgsHelp(pw, "");
         }
diff --git a/services/core/java/com/android/server/am/ContentProviderRecord.java b/services/core/java/com/android/server/am/ContentProviderRecord.java
index 46dfc7c..d8d8ccc 100644
--- a/services/core/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/core/java/com/android/server/am/ContentProviderRecord.java
@@ -38,6 +38,9 @@
 import java.util.ArrayList;
 
 final class ContentProviderRecord implements ComponentName.WithComponentName {
+    // Maximum attempts to bring up the content provider before giving up.
+    static final int MAX_RETRY_COUNT = 3;
+
     final ActivityManagerService service;
     public final ProviderInfo info;
     final int uid;
@@ -54,6 +57,7 @@
     ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
     // Count for external process for which we have no handles.
     int externalProcessNoHandleCount;
+    int mRestartCount; // number of times we tried before bringing up it successfully.
     ProcessRecord proc; // if non-null, hosting process.
     ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
     String stringName;
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
index fd64df9..2081b17 100644
--- a/services/core/java/com/android/server/am/MemoryStatUtil.java
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -39,8 +39,7 @@
  * Static utility methods related to {@link MemoryStat}.
  */
 public final class MemoryStatUtil {
-    static final int BYTES_IN_KILOBYTE = 1024;
-    static final long JIFFY_NANOS = 1_000_000_000 / Os.sysconf(OsConstants._SC_CLK_TCK);
+    static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
 
@@ -52,10 +51,6 @@
     private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
     /** Path to procfs stat file for logging app start memory state */
     private static final String PROC_STAT_FILE_FMT = "/proc/%d/stat";
-    /** Path to procfs status file for logging app memory state */
-    private static final String PROC_STATUS_FILE_FMT = "/proc/%d/status";
-    /** Path to procfs cmdline file. Used with pid: /proc/pid/cmdline. */
-    private static final String PROC_CMDLINE_FILE_FMT = "/proc/%d/cmdline";
 
     private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
     private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
@@ -63,16 +58,9 @@
     private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
     private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
 
-    private static final Pattern PROCFS_RSS_IN_KILOBYTES =
-            Pattern.compile("VmRSS:\\s*(\\d+)\\s*kB");
-    private static final Pattern PROCFS_ANON_RSS_IN_KILOBYTES =
-            Pattern.compile("RssAnon:\\s*(\\d+)\\s*kB");
-    private static final Pattern PROCFS_SWAP_IN_KILOBYTES =
-            Pattern.compile("VmSwap:\\s*(\\d+)\\s*kB");
-
     private static final int PGFAULT_INDEX = 9;
     private static final int PGMAJFAULT_INDEX = 11;
-    private static final int START_TIME_INDEX = 21;
+    private static final int RSS_IN_PAGES_INDEX = 23;
 
     private MemoryStatUtil() {}
 
@@ -106,19 +94,7 @@
     @Nullable
     public static MemoryStat readMemoryStatFromProcfs(int pid) {
         final String statPath = String.format(Locale.US, PROC_STAT_FILE_FMT, pid);
-        final String statusPath = String.format(Locale.US, PROC_STATUS_FILE_FMT, pid);
-        return parseMemoryStatFromProcfs(readFileContents(statPath), readFileContents(statusPath));
-    }
-
-    /**
-     * Reads cmdline of a process from procfs.
-     *
-     * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
-     * if the file is not available.
-     */
-    public static String readCmdlineFromProcfs(int pid) {
-        final String path = String.format(Locale.US, PROC_CMDLINE_FILE_FMT, pid);
-        return parseCmdlineFromProcfs(readFileContents(path));
+        return parseMemoryStatFromProcfs(readFileContents(statPath));
     }
 
     private static String readFileContents(String path) {
@@ -160,31 +136,19 @@
      */
     @VisibleForTesting
     @Nullable
-    static MemoryStat parseMemoryStatFromProcfs(
-            String procStatContents, String procStatusContents) {
+    static MemoryStat parseMemoryStatFromProcfs(String procStatContents) {
         if (procStatContents == null || procStatContents.isEmpty()) {
             return null;
         }
-        if (procStatusContents == null || procStatusContents.isEmpty()) {
-            return null;
-        }
-
         final String[] splits = procStatContents.split(" ");
         if (splits.length < 24) {
             return null;
         }
-
         try {
             final MemoryStat memoryStat = new MemoryStat();
             memoryStat.pgfault = Long.parseLong(splits[PGFAULT_INDEX]);
             memoryStat.pgmajfault = Long.parseLong(splits[PGMAJFAULT_INDEX]);
-            memoryStat.rssInBytes =
-                tryParseLong(PROCFS_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
-            memoryStat.anonRssInBytes =
-                tryParseLong(PROCFS_ANON_RSS_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
-            memoryStat.swapInBytes =
-                tryParseLong(PROCFS_SWAP_IN_KILOBYTES, procStatusContents) * BYTES_IN_KILOBYTE;
-            memoryStat.startTimeNanos = Long.parseLong(splits[START_TIME_INDEX]) * JIFFY_NANOS;
+            memoryStat.rssInBytes = Long.parseLong(splits[RSS_IN_PAGES_INDEX]) * PAGE_SIZE;
             return memoryStat;
         } catch (NumberFormatException e) {
             Slog.e(TAG, "Failed to parse value", e);
@@ -193,23 +157,6 @@
     }
 
     /**
-     * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
-     *
-     * Parsing is required to strip anything after first null byte.
-     */
-    @VisibleForTesting
-    static String parseCmdlineFromProcfs(String cmdline) {
-        if (cmdline == null) {
-            return "";
-        }
-        int firstNullByte = cmdline.indexOf("\0");
-        if (firstNullByte == -1) {
-            return cmdline;
-        }
-        return cmdline.substring(0, firstNullByte);
-    }
-
-    /**
      * Returns whether per-app memcg is available on device.
      */
     static boolean hasMemcg() {
@@ -237,13 +184,9 @@
         public long pgmajfault;
         /** For memcg stats, the anon rss + swap cache size. Otherwise total RSS. */
         public long rssInBytes;
-        /** Number of bytes of the anonymous RSS. Only present for non-memcg stats. */
-        public long anonRssInBytes;
         /** Number of bytes of page cache memory. Only present for memcg stats. */
         public long cacheInBytes;
         /** Number of bytes of swap usage */
         public long swapInBytes;
-        /** Device time when the processes started. */
-        public long startTimeNanos;
     }
 }
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 64f4a35..4a6e63f 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -86,6 +86,7 @@
         DeviceConfig.NAMESPACE_NETD_NATIVE,
         DeviceConfig.NAMESPACE_RUNTIME_NATIVE,
         DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
+        DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
     };
 
     private final String[] mGlobalSettings;
@@ -276,4 +277,4 @@
         String settingValue = Settings.Global.getString(mContentResolver, settingName);
         setProperty(propName, settingValue);
     }
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 5c8e530..8e4474c 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -133,12 +133,12 @@
     static final int CONTINUE_USER_SWITCH_MSG = 20;
     static final int USER_SWITCH_TIMEOUT_MSG = 30;
     static final int START_PROFILES_MSG = 40;
-    static final int SYSTEM_USER_START_MSG = 50;
-    static final int SYSTEM_USER_CURRENT_MSG = 60;
+    static final int USER_START_MSG = 50;
+    static final int USER_CURRENT_MSG = 60;
     static final int FOREGROUND_PROFILE_CHANGED_MSG = 70;
     static final int REPORT_USER_SWITCH_COMPLETE_MSG = 80;
     static final int USER_SWITCH_CALLBACKS_TIMEOUT_MSG = 90;
-    static final int SYSTEM_USER_UNLOCK_MSG = 100;
+    static final int USER_UNLOCK_MSG = 100;
     static final int REPORT_LOCKED_BOOT_COMPLETE_MSG = 110;
     static final int START_USER_SWITCH_FG_MSG = 120;
 
@@ -368,16 +368,18 @@
                 }
             }
 
-            mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
-                    userId, 0));
-            Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
-            intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-            intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
-                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-            mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
-                    new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
-                    Binder.getCallingUid(), Binder.getCallingPid(), userId);
+            if (!mInjector.getUserManager().isPreCreated(userId)) {
+                mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
+                        userId, 0));
+                Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
+                        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                mInjector.broadcastIntent(intent, null, resultTo, 0, null, null,
+                        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
+                        Binder.getCallingUid(), Binder.getCallingPid(), userId);
+            }
         }
 
         // We need to delay unlocking managed profiles until the parent user
@@ -438,8 +440,7 @@
 
             // Dispatch unlocked to system services; when fully dispatched,
             // that calls through to the next "unlocked" phase
-            mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
-                    .sendToTarget();
+            mHandler.obtainMessage(USER_UNLOCK_MSG, userId, 0, uss).sendToTarget();
         });
         return true;
     }
@@ -555,6 +556,17 @@
             }
         }
 
+        if (userInfo.preCreated) {
+            Slog.i(TAG, "Stopping pre-created user " + userInfo.toFullString());
+            // Pre-created user was started right after creation so services could properly
+            // intialize it; it should be stopped right away as it's not really a "real" user.
+            // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback
+            // on SystemService instead.
+            stopUser(userInfo.id, /* force= */ true, /* stopUserCallback= */ null,
+                    /* keyEvictedCallback= */ null);
+            return;
+        }
+
         // Spin up app widgets prior to boot-complete, so they can be ready promptly
         mInjector.startUserWidgets(userId);
 
@@ -799,7 +811,8 @@
             mInjector.systemServiceManagerCleanupUser(userId);
             mInjector.stackSupervisorRemoveUser(userId);
             // Remove the user if it is ephemeral.
-            if (getUserInfo(userId).isEphemeral()) {
+            UserInfo userInfo = getUserInfo(userId);
+            if (userInfo.isEphemeral() && !userInfo.preCreated) {
                 mInjector.getUserManager().removeUserEvenWhenDisallowed(userId);
             }
 
@@ -1069,6 +1082,11 @@
                 return false;
             }
 
+            if (foreground && userInfo.preCreated) {
+                Slog.w(TAG, "Cannot start pre-created user #" + userId + " as foreground");
+                return false;
+            }
+
             if (foreground && mUserSwitchUiEnabled) {
                 t.traceBegin("startFreezingScreen");
                 mInjector.getWindowManager().startFreezingScreen(
@@ -1178,15 +1196,13 @@
                 // Booting up a new user, need to tell system services about it.
                 // Note that this is on the same handler as scheduling of broadcasts,
                 // which is important because it needs to go first.
-                mHandler.sendMessage(
-                        mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
+                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, 0));
                 t.traceEnd();
             }
 
             t.traceBegin("sendMessages");
             if (foreground) {
-                mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
-                        oldUserId));
+                mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));
                 mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
                 mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
                 mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
@@ -1195,6 +1211,10 @@
                         oldUserId, userId, uss), USER_SWITCH_TIMEOUT_MS);
             }
 
+            if (userInfo.preCreated) {
+                needStart = false;
+            }
+
             if (needStart) {
                 // Send USER_STARTED broadcast
                 Intent intent = new Intent(Intent.ACTION_USER_STARTED);
@@ -2168,14 +2188,14 @@
             case START_PROFILES_MSG:
                 startProfiles();
                 break;
-            case SYSTEM_USER_START_MSG:
+            case USER_START_MSG:
                 mInjector.batteryStatsServiceNoteEvent(
                         BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
                         Integer.toString(msg.arg1), msg.arg1);
                 mInjector.getSystemServiceManager().startUser(TimingsTraceAndSlog.newAsyncLog(),
                         msg.arg1);
                 break;
-            case SYSTEM_USER_UNLOCK_MSG:
+            case USER_UNLOCK_MSG:
                 final int userId = msg.arg1;
                 mInjector.getSystemServiceManager().unlockUser(userId);
                 // Loads recents on a worker thread that allows disk I/O
@@ -2184,7 +2204,7 @@
                 });
                 finishUserUnlocked((UserState) msg.obj);
                 break;
-            case SYSTEM_USER_CURRENT_MSG:
+            case USER_CURRENT_MSG:
                 mInjector.batteryStatsServiceNoteEvent(
                         BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH,
                         Integer.toString(msg.arg2), msg.arg2);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index f866314..798185a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -65,6 +65,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
+import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -360,7 +361,7 @@
 
         public int startNesting;
         public ArrayMap<String, Ops> pkgOps;
-        private SparseIntArray opModes;
+        public SparseIntArray opModes;
 
         // true indicates there is an interested observer, false there isn't but it has such an op
         public SparseBooleanArray foregroundOps;
@@ -382,64 +383,6 @@
                     && (pendingState == UID_STATE_CACHED));
         }
 
-        public int getOpModeCount() {
-            return opModes != null ? opModes.size() : 0;
-        }
-
-        public int getOpCodeAt(int index) {
-            return opModes.keyAt(index);
-        }
-
-        public boolean hasOpMode(int code) {
-            return opModes != null && opModes.indexOfKey(code) >= 0;
-        }
-
-        public int getOpMode(int code) {
-            return opModes.get(code);
-        }
-
-        public boolean putOpMode(int code, int mode) {
-            if (mode == AppOpsManager.opToDefaultMode(code)) {
-                return removeOpMode(code);
-            }
-            if (opModes == null) {
-                opModes = new SparseIntArray();
-            }
-            int index = opModes.indexOfKey(code);
-            if (index < 0) {
-                opModes.put(code, mode);
-                return true;
-            }
-            if (opModes.valueAt(index) == mode) {
-                return false;
-            }
-            opModes.setValueAt(index, mode);
-            return true;
-        }
-
-        public boolean removeOpMode(int code) {
-            if (opModes == null) {
-                return false;
-            }
-            int index = opModes.indexOfKey(code);
-            if (index < 0) {
-                return false;
-            }
-            opModes.removeAt(index);
-            if (opModes.size() == 0) {
-                opModes = null;
-            }
-            return true;
-        }
-
-        @Nullable
-        public SparseIntArray cloneOpModes() {
-            if (opModes == null) {
-                return null;
-            }
-            return opModes.clone();
-        }
-
         int evalMode(int op, int mode) {
             if (mode == AppOpsManager.MODE_FOREGROUND) {
                 return state <= AppOpsManager.resolveFirstUnrestrictedUidState(op)
@@ -467,13 +410,14 @@
         public void evalForegroundOps(SparseArray<ArraySet<ModeCallback>> watchers) {
             SparseBooleanArray which = null;
             hasForegroundWatchers = false;
-            for (int i = getOpModeCount() - 1; i >= 0; i--) {
-                int code = getOpCodeAt(i);
-                if (getOpMode(code) == AppOpsManager.MODE_FOREGROUND) {
-                    if (which == null) {
-                        which = new SparseBooleanArray();
+            if (opModes != null) {
+                for (int i = opModes.size() - 1; i >= 0; i--) {
+                    if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+                        if (which == null) {
+                            which = new SparseBooleanArray();
+                        }
+                        evalForegroundWatchers(opModes.keyAt(i), watchers, which);
                     }
-                    evalForegroundWatchers(code, watchers, which);
                 }
             }
             if (pkgOps != null) {
@@ -1121,28 +1065,24 @@
         return resOps;
     }
 
-    @Nullable
-    private ArrayList<AppOpsManager.OpEntry> collectOps(@NonNull UidState uidState,
-            @Nullable int[] ops) {
-        int opModeCount = uidState.getOpModeCount();
-        if (opModeCount == 0) {
+    private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
+        if (uidOps == null) {
             return null;
         }
         ArrayList<AppOpsManager.OpEntry> resOps = null;
         if (ops == null) {
             resOps = new ArrayList<>();
-            for (int i = 0; i < opModeCount; i++) {
-                int code = uidState.getOpCodeAt(i);
-                resOps.add(new OpEntry(code, uidState.getOpMode(code)));
+            for (int j=0; j<uidOps.size(); j++) {
+                resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
             }
         } else {
-            for (int i = 0; i < ops.length; i++) {
-                int code = ops[i];
-                if (uidState.hasOpMode(code)) {
+            for (int j=0; j<ops.length; j++) {
+                int index = uidOps.indexOfKey(ops[j]);
+                if (index >= 0) {
                     if (resOps == null) {
                         resOps = new ArrayList<>();
                     }
-                    resOps.add(new OpEntry(code, uidState.getOpMode(code)));
+                    resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
                 }
             }
         }
@@ -1288,11 +1228,11 @@
             if (uidState == null) {
                 return null;
             }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState, ops);
+            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
             if (resOps == null) {
                 return null;
             }
-            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<>();
+            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
             AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
                     null, uidState.uid, resOps);
             res.add(resPackage);
@@ -1360,14 +1300,29 @@
                     return;
                 }
                 uidState = new UidState(uid);
-                uidState.putOpMode(code, mode);
+                uidState.opModes = new SparseIntArray();
+                uidState.opModes.put(code, mode);
                 mUidStates.put(uid, uidState);
                 scheduleWriteLocked();
-            } else {
-                boolean changed = uidState.putOpMode(code, mode);
-                if (changed) {
+            } else if (uidState.opModes == null) {
+                if (mode != defaultMode) {
+                    uidState.opModes = new SparseIntArray();
+                    uidState.opModes.put(code, mode);
                     scheduleWriteLocked();
                 }
+            } else {
+                if (uidState.opModes.indexOfKey(code) >= 0 && uidState.opModes.get(code) == mode) {
+                    return;
+                }
+                if (mode == defaultMode) {
+                    uidState.opModes.delete(code);
+                    if (uidState.opModes.size() <= 0) {
+                        uidState.opModes = null;
+                    }
+                } else {
+                    uidState.opModes.put(code, mode);
+                }
+                scheduleWriteLocked();
             }
             uidState.evalForegroundOps(mOpModeWatchers);
         }
@@ -1606,13 +1561,16 @@
             for (int i = mUidStates.size() - 1; i >= 0; i--) {
                 UidState uidState = mUidStates.valueAt(i);
 
-                if (uidState.uid == reqUid || reqUid == -1) {
-                    for (int opModeIndex = uidState.getOpModeCount() - 1; opModeIndex >= 0;
-                            opModeIndex--) {
-                        final int code = uidState.getOpCodeAt(opModeIndex);
-
+                SparseIntArray opModes = uidState.opModes;
+                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
+                    final int uidOpCount = opModes.size();
+                    for (int j = uidOpCount - 1; j >= 0; j--) {
+                        final int code = opModes.keyAt(j);
                         if (AppOpsManager.opAllowsReset(code)) {
-                            uidState.removeOpMode(code);
+                            opModes.removeAt(j);
+                            if (opModes.size() <= 0) {
+                                uidState.opModes = null;
+                            }
                             for (String packageName : getPackagesForUid(uidState.uid)) {
                                 callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
                                         mOpModeWatchers.get(code));
@@ -1862,8 +1820,9 @@
             }
             code = AppOpsManager.opToSwitch(code);
             UidState uidState = getUidStateLocked(uid, false);
-            if (uidState != null && uidState.hasOpMode(code)) {
-                final int rawMode = uidState.getOpMode(code);
+            if (uidState != null && uidState.opModes != null
+                    && uidState.opModes.indexOfKey(code) >= 0) {
+                final int rawMode = uidState.opModes.get(code);
                 return raw ? rawMode : uidState.evalMode(code, rawMode);
             }
             Op op = getOpLocked(code, uid, packageName, false, false);
@@ -2032,8 +1991,8 @@
             final int switchCode = AppOpsManager.opToSwitch(code);
             // If there is a non-default per UID policy (we set UID op mode only if
             // non-default) it takes over, otherwise use the per package policy.
-            if (uidState.hasOpMode(switchCode)) {
-                final int uidMode = uidState.evalMode(code, uidState.getOpMode(switchCode));
+            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
+                final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
                 if (uidMode != AppOpsManager.MODE_ALLOWED) {
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
                             + switchCode + " (" + code + ") uid " + uid + " package "
@@ -2334,8 +2293,8 @@
             // If there is a non-default per UID policy (we set UID op mode only if
             // non-default) it takes over, otherwise use the per package policy.
             final int opCode = op.op;
-            if (uidState.hasOpMode(switchCode)) {
-                final int uidMode = uidState.evalMode(code, uidState.getOpMode(switchCode));
+            if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
+                final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
                 if (uidMode != AppOpsManager.MODE_ALLOWED
                         && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
                     if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
@@ -2654,8 +2613,9 @@
                                 || !callback.isWatchingUid(uidState.uid)) {
                             continue;
                         }
-                        boolean doAllPackages = uidState.hasOpMode(code)
-                                && uidState.getOpMode(code) == AppOpsManager.MODE_FOREGROUND;
+                        boolean doAllPackages = uidState.opModes != null
+                                && uidState.opModes.indexOfKey(code) >= 0
+                                && uidState.opModes.get(code) == AppOpsManager.MODE_FOREGROUND;
                         if (uidState.pkgOps != null) {
                             for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
                                 final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
@@ -2978,9 +2938,12 @@
             if (uidState == null) {
                 continue;
             }
-            if (uidState.hasOpMode(AppOpsManager.OP_RUN_IN_BACKGROUND)) {
-                uidState.putOpMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.getOpMode(
-                        AppOpsManager.OP_RUN_IN_BACKGROUND));
+            if (uidState.opModes != null) {
+                final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
+                if (idx >= 0) {
+                    uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+                        uidState.opModes.valueAt(idx));
+                }
             }
             if (uidState.pkgOps == null) {
                 continue;
@@ -3036,7 +2999,10 @@
                 final int code = Integer.parseInt(parser.getAttributeValue(null, "n"));
                 final int mode = Integer.parseInt(parser.getAttributeValue(null, "m"));
                 UidState uidState = getUidStateLocked(uid, true);
-                uidState.putOpMode(code, mode);
+                if (uidState.opModes == null) {
+                    uidState.opModes = new SparseIntArray();
+                }
+                uidState.opModes.put(code, mode);
             } else {
                 Slog.w(TAG, "Unknown element under <uid-ops>: "
                         + parser.getName());
@@ -3188,38 +3154,47 @@
                 out.startTag(null, "app-ops");
                 out.attribute(null, "v", String.valueOf(CURRENT_VERSION));
 
-                final SparseArray<SparseIntArray> uidOpModes = new SparseArray<>();
+                SparseArray<SparseIntArray> uidStatesClone;
                 synchronized (this) {
-                    final int uidStatesSize = mUidStates.size();
-                    for (int i = 0; i < uidStatesSize; i++) {
-                        final SparseIntArray opModes = mUidStates.valueAt(i).cloneOpModes();
-                        if (opModes != null) {
-                            final int uid = mUidStates.keyAt(i);
-                            uidOpModes.put(uid, opModes);
+                    uidStatesClone = new SparseArray<>(mUidStates.size());
+
+                    final int uidStateCount = mUidStates.size();
+                    for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                        UidState uidState = mUidStates.valueAt(uidStateNum);
+                        int uid = mUidStates.keyAt(uidStateNum);
+
+                        SparseIntArray opModes = uidState.opModes;
+                        if (opModes != null && opModes.size() > 0) {
+                            uidStatesClone.put(uid, new SparseIntArray(opModes.size()));
+
+                            final int opCount = opModes.size();
+                            for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+                                uidStatesClone.get(uid).put(
+                                        opModes.keyAt(opCountNum),
+                                        opModes.valueAt(opCountNum));
+                            }
                         }
                     }
                 }
 
-                final int uidOpModesSize = uidOpModes.size();
-                for (int uidOpModesIndex = 0; uidOpModesIndex < uidOpModesSize; uidOpModesIndex++) {
-                    final int uid = uidOpModes.keyAt(uidOpModesIndex);
-                    final SparseIntArray opModes = uidOpModes.valueAt(uidOpModesIndex);
-
-                    out.startTag(null, "uid");
-                    out.attribute(null, "n", Integer.toString(uid));
-
-                    final int opModesSize = opModes.size();
-                    for (int opModesIndex = 0; opModesIndex < opModesSize; opModesIndex++) {
-                        final int code = opModes.keyAt(opModesIndex);
-                        final int mode = opModes.valueAt(opModesIndex);
-
-                        out.startTag(null, "op");
-                        out.attribute(null, "n", Integer.toString(code));
-                        out.attribute(null, "m", Integer.toString(mode));
-                        out.endTag(null, "op");
+                final int uidStateCount = uidStatesClone.size();
+                for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                    SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
+                    if (opModes != null && opModes.size() > 0) {
+                        out.startTag(null, "uid");
+                        out.attribute(null, "n",
+                                Integer.toString(uidStatesClone.keyAt(uidStateNum)));
+                        final int opCount = opModes.size();
+                        for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+                            final int op = opModes.keyAt(opCountNum);
+                            final int mode = opModes.valueAt(opCountNum);
+                            out.startTag(null, "op");
+                            out.attribute(null, "n", Integer.toString(op));
+                            out.attribute(null, "m", Integer.toString(mode));
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
                     }
-
-                    out.endTag(null, "uid");
                 }
 
                 if (allOps != null) {
@@ -4164,22 +4139,21 @@
             }
             for (int i=0; i<mUidStates.size(); i++) {
                 UidState uidState = mUidStates.valueAt(i);
+                final SparseIntArray opModes = uidState.opModes;
                 final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
 
                 if (dumpWatchers || dumpHistory) {
                     continue;
                 }
                 if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
-                    boolean hasOp = dumpOp < 0 || uidState.hasOpMode(dumpOp);
+                    boolean hasOp = dumpOp < 0 || (uidState.opModes != null
+                            && uidState.opModes.indexOfKey(dumpOp) >= 0);
                     boolean hasPackage = dumpPackage == null;
                     boolean hasMode = dumpMode < 0;
-                    if (!hasMode) {
-                        int opModeCount = uidState.getOpModeCount();
-                        for (int opModeIndex = 0; opModeIndex < opModeCount; opModeIndex++) {
-                            int code = uidState.getOpCodeAt(opModeIndex);
-                            if (uidState.getOpMode(code) == dumpMode) {
+                    if (!hasMode && opModes != null) {
+                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
+                            if (opModes.valueAt(opi) == dumpMode) {
                                 hasMode = true;
-                                break;
                             }
                         }
                     }
@@ -4246,18 +4220,20 @@
                 }
                 needSep = true;
 
-                final int opModeCount = uidState.getOpModeCount();
-                for (int opModeIndex = 0; opModeIndex < opModeCount; opModeIndex++) {
-                    final int code = uidState.getOpCodeAt(opModeIndex);
-                    final int mode = uidState.getOpMode(code);
-                    if (dumpOp >= 0 && dumpOp != code) {
-                        continue;
+                if (opModes != null) {
+                    final int opModeCount = opModes.size();
+                    for (int j = 0; j < opModeCount; j++) {
+                        final int code = opModes.keyAt(j);
+                        final int mode = opModes.valueAt(j);
+                        if (dumpOp >= 0 && dumpOp != code) {
+                            continue;
+                        }
+                        if (dumpMode >= 0 && dumpMode != mode) {
+                            continue;
+                        }
+                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
+                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
                     }
-                    if (dumpMode >= 0 && dumpMode != mode) {
-                        continue;
-                    }
-                    pw.print("      "); pw.print(AppOpsManager.opToName(code));
-                    pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
                 }
 
                 if (pkgOps == null) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 77b3fee..a6ac17d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -59,6 +59,7 @@
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
 import android.hardware.hdmi.HdmiTvClient;
+import android.hardware.input.InputManager;
 import android.hardware.usb.UsbManager;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
@@ -545,6 +546,10 @@
     private String mEnabledSurroundFormats;
     private boolean mSurroundModeChanged;
 
+    private boolean mMicMuteFromSwitch;
+    private boolean mMicMuteFromApi;
+    private boolean mMicMuteFromRestrictions;
+
     @GuardedBy("mSettingsLock")
     private int mAssistantUid;
 
@@ -882,6 +887,8 @@
         mRoleObserver.register();
 
         onIndicateSystemReady();
+
+        setMicMuteFromSwitchInput();
     }
 
     RoleObserver mRoleObserver;
@@ -1021,6 +1028,8 @@
 
         sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
                 SENDMSG_QUEUE, 1, 0, null, 0);
+
+        setMicMuteFromSwitchInput();
     }
 
     private void onDispatchAudioServerStateChange(boolean state) {
@@ -1557,12 +1566,13 @@
         AudioSystem.setMasterMute(masterMute);
         broadcastMasterMuteStatus(masterMute);
 
-        boolean microphoneMute = mUserManagerInternal.getUserRestriction(
+        mMicMuteFromRestrictions = mUserManagerInternal.getUserRestriction(
                 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
         if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
+            Log.d(TAG, String.format("Mic mute %b, user=%d", mMicMuteFromRestrictions,
+                    currentUser));
         }
-        AudioSystem.muteMicrophone(microphoneMute);
+        setMicrophoneMuteNoCallerCheck(currentUser);
     }
 
     private int rescaleIndex(int index, int srcStream, int dstStream) {
@@ -2837,20 +2847,45 @@
                 != PackageManager.PERMISSION_GRANTED) {
             return;
         }
-        setMicrophoneMuteNoCallerCheck(on, userId);
+        mMicMuteFromApi = on;
+        setMicrophoneMuteNoCallerCheck(userId);
     }
 
-    private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
+    /** @see AudioManager#setMicrophoneMuteFromSwitch(boolean) */
+    public void setMicrophoneMuteFromSwitch(boolean on) {
+        int userId = Binder.getCallingUid();
+        if (userId != android.os.Process.SYSTEM_UID) {
+            Log.e(TAG, "setMicrophoneMuteFromSwitch() called from non system user!");
+            return;
+        }
+        mMicMuteFromSwitch = on;
+        setMicrophoneMuteNoCallerCheck(userId);
+    }
+
+    private void setMicMuteFromSwitchInput() {
+        InputManager im = mContext.getSystemService(InputManager.class);
+        final int isMicMuted = im.isMicMuted();
+        if (isMicMuted != InputManager.SWITCH_STATE_UNKNOWN) {
+            setMicrophoneMuteFromSwitch(im.isMicMuted() != InputManager.SWITCH_STATE_OFF);
+        }
+    }
+
+    public boolean isMicrophoneMuted() {
+        return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi;
+    }
+
+    private void setMicrophoneMuteNoCallerCheck(int userId) {
+        final boolean muted = isMicrophoneMuted();
         if (DEBUG_VOL) {
-            Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
+            Log.d(TAG, String.format("Mic mute %b, user=%d", muted, userId));
         }
         // only mute for the current user
-        if (getCurrentUserId() == userId) {
+        if (getCurrentUserId() == userId || userId == android.os.Process.SYSTEM_UID) {
             final boolean currentMute = AudioSystem.isMicrophoneMuted();
             final long identity = Binder.clearCallingIdentity();
-            AudioSystem.muteMicrophone(on);
+            AudioSystem.muteMicrophone(muted);
             Binder.restoreCallingIdentity(identity);
-            if (on != currentMute) {
+            if (muted != currentMute) {
                 mContext.sendBroadcastAsUser(
                         new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
                                 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
@@ -3854,7 +3889,7 @@
         final boolean muteSystem = (zenPolicy.priorityCategories
                 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0;
         final boolean muteNotificationAndRing = ZenModeConfig
-                .areAllPriorityOnlyNotificationZenSoundsMuted(
+                .areAllPriorityOnlyRingerSoundsMuted(
                         mNm.getConsolidatedNotificationPolicy());
         return muteAlarms && isAlarm(streamType)
                 || muteMedia && isMedia(streamType)
@@ -3867,16 +3902,26 @@
     }
 
     /**
-     * DND total silence: media and alarms streams are tied to the muted ringer
+     * Notifications, ringer and system sounds are controlled by the ringer:
      * {@link ZenModeHelper.RingerModeDelegate#getRingerModeAffectedStreams(int)}
-     * DND alarms only: notification, ringer + system muted (by default tied to muted ringer mode)
-     * DND priority only: alarms, media, system streams can be muted separate from ringer based on
+     * DND total silence: media and alarms streams can be muted by DND
+     * DND alarms only: no streams additionally controlled by DND
+     * DND priority only: alarms, media, system streams can be muted by DND based on
      * zenPolicy (this method determines which streams)
      * @return true if changed, else false
      */
     private boolean updateZenModeAffectedStreams() {
+        if (!mSystemReady) {
+            return false;
+        }
+
         int zenModeAffectedStreams = 0;
-        if (mSystemReady && mNm.getZenMode() == Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+        final int zenMode = mNm.getZenMode();
+
+        if (zenMode == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS) {
+            zenModeAffectedStreams |= 1 << AudioManager.STREAM_ALARM;
+            zenModeAffectedStreams |= 1 << AudioManager.STREAM_MUSIC;
+        } else if (zenMode == Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
             NotificationManager.Policy zenPolicy = mNm.getConsolidatedNotificationPolicy();
             if ((zenPolicy.priorityCategories
                     & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) == 0) {
@@ -3888,6 +3933,8 @@
                 zenModeAffectedStreams |= 1 << AudioManager.STREAM_MUSIC;
             }
 
+            // even if zen isn't muting the system stream, the ringer mode can still mute
+            // the system stream
             if ((zenPolicy.priorityCategories
                     & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0) {
                 zenModeAffectedStreams |= 1 << AudioManager.STREAM_SYSTEM;
@@ -5378,7 +5425,8 @@
                 final boolean isRestricted =
                         newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
                 if (wasRestricted != isRestricted) {
-                    setMicrophoneMuteNoCallerCheck(isRestricted, userId);
+                    mMicMuteFromRestrictions = isRestricted;
+                    setMicrophoneMuteNoCallerCheck(userId);
                 }
             }
 
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 7302b98..3d341ef 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -25,7 +25,6 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
 
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
 import android.app.IActivityManager;
 import android.app.KeyguardManager;
 import android.app.UserSwitchObserver;
@@ -257,12 +256,11 @@
     private final Injector mInjector;
     @VisibleForTesting
     final IBiometricService.Stub mImpl;
-    private final AppOpsManager mAppOps;
     private final boolean mHasFeatureFingerprint;
     private final boolean mHasFeatureIris;
     private final boolean mHasFeatureFace;
     @VisibleForTesting
-    SettingObserver mSettingObserver;
+    final SettingObserver mSettingObserver;
     private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
     private final Random mRandom = new Random();
 
@@ -411,8 +409,8 @@
     };
 
     private final class Authenticator {
-        int mType;
-        BiometricAuthenticator mAuthenticator;
+        final int mType;
+        final BiometricAuthenticator mAuthenticator;
 
         Authenticator(int type, BiometricAuthenticator authenticator) {
             mType = type;
@@ -445,9 +443,9 @@
         private final ContentResolver mContentResolver;
         private final List<BiometricService.EnabledOnKeyguardCallback> mCallbacks;
 
-        private Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
-        private Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
-        private Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
+        private final Map<Integer, Boolean> mFaceEnabledOnKeyguard = new HashMap<>();
+        private final Map<Integer, Boolean> mFaceEnabledForApps = new HashMap<>();
+        private final Map<Integer, Boolean> mFaceAlwaysRequireConfirmation = new HashMap<>();
 
         /**
          * Creates a content observer.
@@ -864,14 +862,6 @@
         }
     }
 
-    private void checkAppOp(String opPackageName, int callingUid) {
-        if (mAppOps.noteOp(AppOpsManager.OP_USE_BIOMETRIC, callingUid,
-                opPackageName) != AppOpsManager.MODE_ALLOWED) {
-            Slog.w(TAG, "Rejecting " + opPackageName + "; permission denied");
-            throw new SecurityException("Permission denied");
-        }
-    }
-
     private void checkInternalPermission() {
         getContext().enforceCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL,
                 "Must have USE_BIOMETRIC_INTERNAL permission");
@@ -942,7 +932,6 @@
 
         mInjector = injector;
         mImpl = new BiometricServiceWrapper();
-        mAppOps = context.getSystemService(AppOpsManager.class);
         mEnabledOnKeyguardCallbacks = new ArrayList<>();
         mSettingObserver = mInjector.getSettingObserver(context, mHandler,
                 mEnabledOnKeyguardCallbacks);
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index b1c7c76..9eb0d50 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -930,7 +930,8 @@
                     final Face face = new Face("", 0 /* identifier */, deviceId);
                     FaceService.super.handleRemoved(face, 0 /* remaining */);
                 }
-
+                Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                        Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT);
             });
         }
 
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 66bd27c..aea6d8d 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import android.annotation.NonNull;
 import android.net.ConnectivityManager;
 import android.net.IDnsResolver;
 import android.net.INetd;
@@ -325,13 +326,13 @@
      * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
      * has no idea that 464xlat is running on top of it.
      */
-    public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) {
+    public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) {
         lp.setNat64Prefix(mNat64Prefix);
 
         if (!isRunning()) {
             return;
         }
-        if (lp == null || lp.getAllInterfaceNames().contains(mIface)) {
+        if (lp.getAllInterfaceNames().contains(mIface)) {
             return;
         }
 
@@ -434,7 +435,7 @@
 
     @Override
     public void interfaceRemoved(String iface) {
-        mNetwork.handler().post(() -> { handleInterfaceRemoved(iface); });
+        mNetwork.handler().post(() -> handleInterfaceRemoved(iface));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7b3eae1..6b70e5f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -199,13 +199,22 @@
      */
     private @NonNull List<String> mLockdownWhitelist = Collections.emptyList();
 
-    /**
-     * List of UIDs for which networking should be blocked until VPN is ready, during brief periods
-     * when VPN is not running. For example, during system startup or after a crash.
+     /**
+     * A memory of what UIDs this class told netd to block for the lockdown feature.
+     *
+     * Netd maintains ranges of UIDs for which network should be restricted to using only the VPN
+     * for the lockdown feature. This class manages these UIDs and sends this information to netd.
+     * To avoid sending the same commands multiple times (which would be wasteful) and to be able
+     * to revoke lists (when the rules should change), it's simplest to keep this cache of what
+     * netd knows, so it can be diffed and sent most efficiently.
+     *
+     * The contents of this list must only be changed when updating the UIDs lists with netd,
+     * since it needs to keep in sync with the picture netd has of them.
+     *
      * @see mLockdown
      */
     @GuardedBy("this")
-    private Set<UidRange> mBlockedUsers = new ArraySet<>();
+    private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>();
 
     // Handle of the user initiating VPN.
     private final int mUserHandle;
@@ -254,7 +263,7 @@
     }
 
     /**
-     * Update current state, dispaching event to listeners.
+     * Update current state, dispatching event to listeners.
      */
     @VisibleForTesting
     protected void updateState(DetailedState detailedState, String reason) {
@@ -1325,7 +1334,7 @@
      *                {@link Vpn} goes through a VPN connection or is blocked until one is
      *                available, {@code false} to lift the requirement.
      *
-     * @see #mBlockedUsers
+     * @see #mBlockedUidsAsToldToNetd
      */
     @GuardedBy("this")
     private void setVpnForcedLocked(boolean enforce) {
@@ -1336,37 +1345,47 @@
             exemptedPackages = new ArrayList<>(mLockdownWhitelist);
             exemptedPackages.add(mPackage);
         }
-        final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
+        final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd);
 
-        Set<UidRange> addedRanges = Collections.emptySet();
+        final Set<UidRange> rangesToTellNetdToAdd;
         if (enforce) {
-            addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
-                    /* allowedApplications */ null,
-                    /* disallowedApplications */ exemptedPackages);
+            final Set<UidRange> rangesThatShouldBeBlocked =
+                    createUserAndRestrictedProfilesRanges(mUserHandle,
+                            /* allowedApplications */ null,
+                            /* disallowedApplications */ exemptedPackages);
 
             // The UID range of the first user (0-99999) would block the IPSec traffic, which comes
             // directly from the kernel and is marked as uid=0. So we adjust the range to allow
             // it through (b/69873852).
-            for (UidRange range : addedRanges) {
+            for (UidRange range : rangesThatShouldBeBlocked) {
                 if (range.start == 0) {
-                    addedRanges.remove(range);
+                    rangesThatShouldBeBlocked.remove(range);
                     if (range.stop != 0) {
-                        addedRanges.add(new UidRange(1, range.stop));
+                        rangesThatShouldBeBlocked.add(new UidRange(1, range.stop));
                     }
                 }
             }
 
-            removedRanges.removeAll(addedRanges);
-            addedRanges.removeAll(mBlockedUsers);
+            rangesToTellNetdToRemove.removeAll(rangesThatShouldBeBlocked);
+            rangesToTellNetdToAdd = rangesThatShouldBeBlocked;
+            // The ranges to tell netd to add are the ones that should be blocked minus the
+            // ones it already knows to block. Note that this will change the contents of
+            // rangesThatShouldBeBlocked, but the list of ranges that should be blocked is
+            // not used after this so it's fine to destroy it.
+            rangesToTellNetdToAdd.removeAll(mBlockedUidsAsToldToNetd);
+        } else {
+            rangesToTellNetdToAdd = Collections.emptySet();
         }
 
-        setAllowOnlyVpnForUids(false, removedRanges);
-        setAllowOnlyVpnForUids(true, addedRanges);
+        // If mBlockedUidsAsToldToNetd used to be empty, this will always be a no-op.
+        setAllowOnlyVpnForUids(false, rangesToTellNetdToRemove);
+        // If nothing should be blocked now, this will now be a no-op.
+        setAllowOnlyVpnForUids(true, rangesToTellNetdToAdd);
     }
 
     /**
-     * Either add or remove a list of {@link UidRange}s to the list of UIDs that are only allowed
-     * to make connections through sockets that have had {@code protect()} called on them.
+     * Tell netd to add or remove a list of {@link UidRange}s to the list of UIDs that are only
+     * allowed to make connections through sockets that have had {@code protect()} called on them.
      *
      * @param enforce {@code true} to add to the blacklist, {@code false} to remove.
      * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is
@@ -1388,9 +1407,9 @@
             return false;
         }
         if (enforce) {
-            mBlockedUsers.addAll(ranges);
+            mBlockedUidsAsToldToNetd.addAll(ranges);
         } else {
-            mBlockedUsers.removeAll(ranges);
+            mBlockedUidsAsToldToNetd.removeAll(ranges);
         }
         return true;
     }
@@ -1557,17 +1576,18 @@
     /**
      * @param uid The target uid.
      *
-     * @return {@code true} if {@code uid} is included in one of the mBlockedUsers ranges and the
-     * VPN is not connected, or if the VPN is connected but does not apply to the {@code uid}.
+     * @return {@code true} if {@code uid} is included in one of the mBlockedUidsAsToldToNetd
+     * ranges and the VPN is not connected, or if the VPN is connected but does not apply to
+     * the {@code uid}.
      *
      * @apiNote This method don't check VPN lockdown status.
-     * @see #mBlockedUsers
+     * @see #mBlockedUidsAsToldToNetd
      */
     public synchronized boolean isBlockingUid(int uid) {
         if (mNetworkInfo.isConnected()) {
             return !appliesToUid(uid);
         } else {
-            return UidRange.containsUid(mBlockedUsers, uid);
+            return UidRange.containsUid(mBlockedUidsAsToldToNetd, uid);
         }
     }
 
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 e8a5779..88a7077 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -64,7 +64,13 @@
     AmbientFilter mColorTemperatureFilter;
     private DisplayWhiteBalanceThrottler mThrottler;
 
+    // In low brightness conditions the ALS readings are more noisy and produce
+    // high errors. This default is introduced to provide a fixed display color
+    // temperature when sensor readings become unreliable.
     private final float mLowLightAmbientColorTemperature;
+    // In high brightness conditions certain color temperatures can cause peak display
+    // brightness to drop. This fixed color temperature can be used to compensate for
+    // this effect.
     private final float mHighLightAmbientColorTemperature;
 
     private float mAmbientColorTemperature;
@@ -85,12 +91,14 @@
     // A piecewise linear relationship between ambient and display color temperatures.
     private Spline.LinearSpline mAmbientToDisplayColorTemperatureSpline;
 
-    // In very low or very high brightness conditions ambient EQ should to set to a default
-    // instead of using mAmbientToDisplayColorTemperatureSpline. However, setting ambient EQ
-    // based on thresholds can cause the display to rapidly change color temperature. To solve
-    // this, mLowLightAmbientBrightnessToBiasSpline and mHighLightAmbientBrightnessToBiasSpline
-    // are used to smoothly interpolate from ambient color temperature to the defaults.
-    // A piecewise linear relationship between low light brightness and low light bias.
+    // In very low or very high brightness conditions Display White Balance should
+    // be to set to a default instead of using mAmbientToDisplayColorTemperatureSpline.
+    // However, setting Display White Balance based on thresholds can cause the
+    // display to rapidly change color temperature. To solve this,
+    // mLowLightAmbientBrightnessToBiasSpline and
+    // mHighLightAmbientBrightnessToBiasSpline are used to smoothly interpolate from
+    // ambient color temperature to the defaults. A piecewise linear relationship
+    // between low light brightness and low light bias.
     private Spline.LinearSpline mLowLightAmbientBrightnessToBiasSpline;
 
     // A piecewise linear relationship between high light brightness and high light bias.
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index cfbf8bc..96ba8ef 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -394,10 +394,6 @@
     static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
     static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv";
 
-    // Property name for the local device configurations.
-    // TODO(OEM): OEM should provide this property, and the value is the comma separated integer
-    //     values which denotes the device type in HDMI Spec 1.4.
-    static final String PROPERTY_DEVICE_TYPE = "ro.hdmi.device_type";
 
     // TODO(OEM): Set this to false to keep the playback device in sleep upon hotplug event.
     //            True by default.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3856de4..c3354e1 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -56,8 +56,8 @@
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputManager.TvInputCallback;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -68,6 +68,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
+import android.sysprop.HdmiProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -95,6 +96,8 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * Provides a service for sending and processing HDMI control messages,
@@ -452,7 +455,14 @@
 
     public HdmiControlService(Context context) {
         super(context);
-        mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE));
+        List<Integer> deviceTypes = HdmiProperties.device_type();
+        if (deviceTypes.contains(null)) {
+            Slog.w(TAG, "Error parsing ro.hdmi.device.type: " + SystemProperties.get(
+                    "ro.hdmi.device_type"));
+            deviceTypes = deviceTypes.stream().filter(Objects::nonNull).collect(
+                    Collectors.toList());
+        }
+        mLocalDevices = deviceTypes;
         mSettingsObserver = new SettingsObserver(mHandler);
     }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 75b9705..7e6e668 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -47,6 +47,7 @@
 import android.hardware.input.InputManagerInternal;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
+import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -220,6 +221,8 @@
     private static native void nativeSetFocusedApplication(long ptr,
             int displayId, InputApplicationHandle application);
     private static native void nativeSetFocusedDisplay(long ptr, int displayId);
+    private static native boolean nativeTransferTouchFocus(long ptr,
+            InputChannel fromChannel, InputChannel toChannel);
     private static native void nativeSetPointerSpeed(long ptr, int speed);
     private static native void nativeSetShowTouches(long ptr, boolean enabled);
     private static native void nativeSetInteractive(long ptr, boolean interactive);
@@ -294,6 +297,9 @@
     /** Switch code: Camera lens cover. When set the lens is covered. */
     public static final int SW_CAMERA_LENS_COVER = 0x09;
 
+    /** Switch code: Microphone. When set it is off. */
+    public static final int SW_MUTE_DEVICE = 0x0e;
+
     public static final int SW_LID_BIT = 1 << SW_LID;
     public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
     public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
@@ -304,6 +310,7 @@
     public static final int SW_JACK_BITS =
             SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_JACK_PHYSICAL_INSERT_BIT | SW_LINEOUT_INSERT_BIT;
     public static final int SW_CAMERA_LENS_COVER_BIT = 1 << SW_CAMERA_LENS_COVER;
+    public static final int SW_MUTE_DEVICE_BIT = 1 << SW_MUTE_DEVICE;
 
     /** Whether to use the dev/input/event or uevent subsystem for the audio jack. */
     final boolean mUseDevInputEventForAudioJack;
@@ -970,6 +977,11 @@
     }
 
     @Override // Binder call
+    public int isMicMuted() {
+        return getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MUTE_DEVICE);
+    }
+
+    @Override // Binder call
     public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE,
                 "registerTabletModeChangedListener()")) {
@@ -1533,6 +1545,29 @@
         nativeSetSystemUiVisibility(mPtr, visibility);
     }
 
+    /**
+     * Atomically transfers touch focus from one window to another as identified by
+     * their input channels.  It is possible for multiple windows to have
+     * touch focus if they support split touch dispatch
+     * {@link android.view.WindowManager.LayoutParams#FLAG_SPLIT_TOUCH} but this
+     * method only transfers touch focus of the specified window without affecting
+     * other windows that may also have touch focus at the same time.
+     * @param fromChannel The channel of a window that currently has touch focus.
+     * @param toChannel The channel of the window that should receive touch focus in
+     * place of the first.
+     * @return True if the transfer was successful.  False if the window with the
+     * specified channel did not actually have touch focus at the time of the request.
+     */
+    public boolean transferTouchFocus(InputChannel fromChannel, InputChannel toChannel) {
+        if (fromChannel == null) {
+            throw new IllegalArgumentException("fromChannel must not be null.");
+        }
+        if (toChannel == null) {
+            throw new IllegalArgumentException("toChannel must not be null.");
+        }
+        return nativeTransferTouchFocus(mPtr, fromChannel, toChannel);
+    }
+
     @Override // Binder call
     public void tryPointerSpeed(int speed) {
         if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
@@ -1779,6 +1814,12 @@
             mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
                     args).sendToTarget();
         }
+
+        if ((switchMask & SW_MUTE_DEVICE_BIT) != 0) {
+            final boolean micMute = ((switchValues & SW_MUTE_DEVICE_BIT) != 0);
+            AudioManager audioManager = mContext.getSystemService(AudioManager.class);
+            audioManager.setMicrophoneMuteFromSwitch(micMute);
+        }
     }
 
     // Native callback.
diff --git a/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java b/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java
new file mode 100644
index 0000000..c2ed3df
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/engine/AppInstallMetadata.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.engine;
+
+/**
+ * The app install metadata.
+ *
+ * <p>The integrity component retrieves metadata for app installs from package manager, passing it
+ * to the rule evaluation engine to evaluate the metadata against the rules.
+ */
+public final class AppInstallMetadata {
+    final String mPackageName;
+    // Raw string encoding for the SHA-256 hash of the certificate of the app.
+    final String mAppCertificate;
+    final String mInstallerName;
+    // Raw string encoding for the SHA-256 hash of the certificate of the installer.
+    final String mInstallerCertificate;
+    final int mVersionCode;
+    final boolean mIsPreInstalled;
+
+    AppInstallMetadata(String packageName, String appCertificate, String installerName,
+            String installerCertificate, int versionCode, boolean isPreInstalled) {
+        this.mPackageName = packageName;
+        this.mAppCertificate = appCertificate;
+        this.mInstallerName = installerName;
+        this.mInstallerCertificate = installerCertificate;
+        this.mVersionCode = versionCode;
+        this.mIsPreInstalled = isPreInstalled;
+    }
+}
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java
new file mode 100644
index 0000000..93c9ada
--- /dev/null
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluation.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.integrity.engine;
+
+/**
+ * The engine used to evaluate rules against app installs.
+ *
+ * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine
+ * to allow/block that install.
+ */
+public final class RuleEvaluation {
+    private static final String TAG = "RuleEvaluation";
+
+    // TODO: Add singleton injection.
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index b7eca29..378d9eb 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -44,6 +44,7 @@
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DeviceStateCache;
 import android.app.admin.PasswordMetrics;
 import android.app.backup.BackupManager;
 import android.app.trust.IStrongAuthTracker;
@@ -76,6 +77,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
@@ -429,6 +431,10 @@
             return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         }
 
+        public UserManagerInternal getUserManagerInternal() {
+            return LocalServices.getService(UserManagerInternal.class);
+        }
+
         /**
          * Return the {@link DevicePolicyManager} object.
          *
@@ -440,6 +446,10 @@
             return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         }
 
+        public DeviceStateCache getDeviceStateCache() {
+            return DeviceStateCache.getInstance();
+        }
+
         public KeyStore getKeyStore() {
             return KeyStore.getInstance();
         }
@@ -1023,11 +1033,16 @@
     }
 
     private void notifySeparateProfileChallengeChanged(int userId) {
-        final DevicePolicyManagerInternal dpmi = LocalServices.getService(
-                DevicePolicyManagerInternal.class);
-        if (dpmi != null) {
-            dpmi.reportSeparateProfileChallengeChanged(userId);
-        }
+        // LSS cannot call into DPM directly, otherwise it will cause deadlock.
+        // In this case, calling DPM on a handler thread is OK since DPM doesn't
+        // expect reportSeparateProfileChallengeChanged() to happen synchronously.
+        mHandler.post(() -> {
+            final DevicePolicyManagerInternal dpmi = LocalServices.getService(
+                    DevicePolicyManagerInternal.class);
+            if (dpmi != null) {
+                dpmi.reportSeparateProfileChallengeChanged(userId);
+            }
+        });
     }
 
     @Override
@@ -2038,7 +2053,6 @@
      * reporting the password changed.
      */
     private void notifyPasswordChanged(@UserIdInt int userId) {
-        // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
         mHandler.post(() -> {
             mInjector.getDevicePolicyManager().reportPasswordChanged(userId);
             LocalServices.getService(WindowManagerInternal.class).reportPasswordChanged(userId);
@@ -3026,45 +3040,43 @@
         pw.decreaseIndent();
     }
 
+    /**
+     * Cryptographically disable escrow token support for the current user, if the user is not
+     * managed (either user has a profile owner, or if device is managed). Do not disable
+     * if we are running an automotive build.
+     */
     private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
-        long ident = Binder.clearCallingIdentity();
-        try {
-            // Managed profile should have escrow enabled
-            if (mUserManager.getUserInfo(userId).isManagedProfile()) {
-                Slog.i(TAG, "Managed profile can have escrow token");
-                return;
-            }
-            DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
-            // Devices with Device Owner should have escrow enabled on all users.
-            if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
-                Slog.i(TAG, "Corp-owned device can have escrow token");
-                return;
-            }
-            // We could also have a profile owner on the given (non-managed) user for unicorn cases
-            if (dpm.getProfileOwnerAsUser(userId) != null) {
-                Slog.i(TAG, "User with profile owner can have escrow token");
-                return;
-            }
-            // If the device is yet to be provisioned (still in SUW), there is still
-            // a chance that Device Owner will be set on the device later, so postpone
-            // disabling escrow token for now.
-            if (!dpm.isDeviceProvisioned()) {
-                Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
-                return;
-            }
+        final UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal();
 
-            // Escrow tokens are enabled on automotive builds.
-            if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-                return;
-            }
+        // Managed profile should have escrow enabled
+        if (userManagerInternal.isUserManaged(userId)) {
+            Slog.i(TAG, "Managed profile can have escrow token");
+            return;
+        }
 
-            // Disable escrow token permanently on all other device/user types.
-            Slog.i(TAG, "Disabling escrow token on user " + userId);
-            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
-                mSpManager.destroyEscrowData(userId);
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+        // Devices with Device Owner should have escrow enabled on all users.
+        if (userManagerInternal.isDeviceManaged()) {
+            Slog.i(TAG, "Corp-owned device can have escrow token");
+            return;
+        }
+
+        // If the device is yet to be provisioned (still in SUW), there is still
+        // a chance that Device Owner will be set on the device later, so postpone
+        // disabling escrow token for now.
+        if (!mInjector.getDeviceStateCache().isDeviceProvisioned()) {
+            Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
+            return;
+        }
+
+        // Escrow tokens are enabled on automotive builds.
+        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+            return;
+        }
+
+        // Disable escrow token permanently on all other device/user types.
+        Slog.i(TAG, "Disabling escrow token on user " + userId);
+        if (isSyntheticPasswordBasedCredentialLocked(userId)) {
+            mSpManager.destroyEscrowData(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index ea0fb47..9246311 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -129,6 +129,9 @@
             keyStore.load(null);
 
             SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
+            if (decryptionKey == null) {
+                throw new IllegalStateException("SP key is missing: " + keyAlias);
+            }
             byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob);
             return decrypt(decryptionKey, intermediate);
         } catch (Exception e) {
@@ -143,6 +146,9 @@
             keyStore.load(null);
 
             SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
+            if (decryptionKey == null) {
+                throw new IllegalStateException("SP key is missing: " + keyAlias);
+            }
             byte[] intermediate = decrypt(decryptionKey, blob);
             return decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
         } catch (CertificateException | IOException | BadPaddingException
@@ -193,6 +199,7 @@
             keyStore = KeyStore.getInstance("AndroidKeyStore");
             keyStore.load(null);
             keyStore.deleteEntry(keyAlias);
+            Slog.i(TAG, "SP key deleted: " + keyAlias);
         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
                 | IOException e) {
             Slog.e(TAG, "Failed to destroy blob", e);
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index f63aa52..6510923 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1179,7 +1179,7 @@
 
             if (mZenMode == Global.ZEN_MODE_OFF
                     || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
-                    && !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig))) {
+                    && !ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(mConfig))) {
                 // in priority only with ringer not muted, save ringer mode changes
                 // in dnd off, save ringer mode changes
                 setPreviousRingerModeSetting(ringerModeNew);
@@ -1200,7 +1200,7 @@
                             && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
                             || mZenMode == Global.ZEN_MODE_ALARMS
                             || (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
-                            && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(
+                            && ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(
                             mConfig)))) {
                         newZen = Global.ZEN_MODE_OFF;
                     } else if (mZenMode != Global.ZEN_MODE_OFF) {
@@ -1264,29 +1264,21 @@
 
         @Override
         public int getRingerModeAffectedStreams(int streams) {
-            // ringtone and notification streams are always affected by ringer mode
-            // system stream is affected by ringer mode when not in priority-only
+            // ringtone, notification and system streams are always affected by ringer mode
+            // zen muting is handled in AudioService.java's mZenModeAffectedStreams
             streams |= (1 << AudioSystem.STREAM_RING) |
                     (1 << AudioSystem.STREAM_NOTIFICATION) |
                     (1 << AudioSystem.STREAM_SYSTEM);
 
             if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
-                // alarm and music streams affected by ringer mode when in total silence
+                // alarm and music streams affected by ringer mode (cannot be adjusted) when in
+                // total silence
                 streams |= (1 << AudioSystem.STREAM_ALARM) |
                         (1 << AudioSystem.STREAM_MUSIC);
             } else {
                 streams &= ~((1 << AudioSystem.STREAM_ALARM) |
                         (1 << AudioSystem.STREAM_MUSIC));
             }
-
-            if (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
-                    && ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig)) {
-                // system stream is not affected by ringer mode in priority only when the ringer
-                // is zen muted (all other notification categories are muted)
-                streams &= ~(1 << AudioSystem.STREAM_SYSTEM);
-            } else {
-                streams |= (1 << AudioSystem.STREAM_SYSTEM);
-            }
             return streams;
         }
     }
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 288ef0e..f3c9128 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -30,20 +30,17 @@
 import android.util.Slog;
 
 import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper;
-import com.android.server.pm.Installer;
 
 import java.io.File;
 
 /**
  * Handle the creation and deletion of idmap files.
  *
- * The actual work is performed by the idmap binary, launched through Installer
- * and installd (or idmap2).
+ * The actual work is performed by the idmap binary, launched through idmap2d.
  *
  * Note: this class is subclassed in the OMS unit tests, and hence not marked as final.
  */
 class IdmapManager {
-    private static final boolean FEATURE_FLAG_IDMAP2 = true;
     private static final boolean VENDOR_IS_Q_OR_LATER;
     static {
         final String value = SystemProperties.get("ro.vndk.version", "29");
@@ -58,12 +55,10 @@
         VENDOR_IS_Q_OR_LATER = isQOrLater;
     }
 
-    private final Installer mInstaller;
     private final PackageManagerHelper mPackageManager;
     private final IdmapDaemon mIdmapDaemon;
 
-    IdmapManager(final Installer installer, final PackageManagerHelper packageManager) {
-        mInstaller = installer;
+    IdmapManager(final PackageManagerHelper packageManager) {
         mPackageManager = packageManager;
         mIdmapDaemon = IdmapDaemon.getInstance();
     }
@@ -78,18 +73,13 @@
         final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
         final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
         try {
-            if (FEATURE_FLAG_IDMAP2) {
-                int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
-                boolean enforce = enforceOverlayable(overlayPackage);
-                if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
-                    return true;
-                }
-                return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
-                        enforce, userId) != null;
-            } else {
-                mInstaller.idmap(targetPath, overlayPath, sharedGid);
+            int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
+            boolean enforce = enforceOverlayable(overlayPackage);
+            if (mIdmapDaemon.verifyIdmap(overlayPath, policies, enforce, userId)) {
                 return true;
             }
+            return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+                    enforce, userId) != null;
         } catch (Exception e) {
             Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
                     + overlayPath + ": " + e.getMessage());
@@ -102,12 +92,7 @@
             Slog.d(TAG, "remove idmap for " + oi.baseCodePath);
         }
         try {
-            if (FEATURE_FLAG_IDMAP2) {
-                return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
-            } else {
-                mInstaller.removeIdmap(oi.baseCodePath);
-                return true;
-            }
+            return mIdmapDaemon.removeIdmap(oi.baseCodePath, userId);
         } catch (Exception e) {
             Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage());
             return false;
@@ -125,19 +110,12 @@
 
     private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath,
             final int userId) {
-        if (FEATURE_FLAG_IDMAP2) {
-            try {
-                return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
-            } catch (Exception e) {
-                Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
-                        + e.getMessage());
-                return "";
-            }
-        } else {
-            final StringBuilder sb = new StringBuilder("/data/resource-cache/");
-            sb.append(overlayPackagePath.substring(1).replace('/', '@'));
-            sb.append("@idmap");
-            return sb.toString();
+        try {
+            return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId);
+        } catch (Exception e) {
+            Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": "
+                    + e.getMessage());
+            return "";
         }
     }
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f8b3fb2..83bea9d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -62,7 +62,6 @@
 import com.android.server.IoThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
-import com.android.server.pm.Installer;
 import com.android.server.pm.UserManagerService;
 
 import libcore.util.EmptyArray;
@@ -230,8 +229,7 @@
 
     private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
 
-    public OverlayManagerService(@NonNull final Context context,
-            @NonNull final Installer installer) {
+    public OverlayManagerService(@NonNull final Context context) {
         super(context);
         try {
             traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
@@ -239,7 +237,7 @@
                     new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
             mPackageManager = new PackageManagerHelper();
             mUserManager = UserManagerService.getInstance();
-            IdmapManager im = new IdmapManager(installer, mPackageManager);
+            IdmapManager im = new IdmapManager(mPackageManager);
             mSettings = new OverlayManagerSettings();
             mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
                     getDefaultOverlayPackages(), new OverlayChangeListener());
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 3464cab..2b6c347 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -62,6 +62,7 @@
 import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -1024,8 +1025,22 @@
             }
 
             @Override
-            public void onPackagesSuspended(String[] packages, Bundle launcherExtras) {
+            public void onPackagesSuspended(String[] packages) {
                 UserHandle user = new UserHandle(getChangingUserId());
+                PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+                final ArrayList<Pair<String, Bundle>> packagesWithExtras = new ArrayList<>();
+                final ArrayList<String> packagesWithoutExtras = new ArrayList<>();
+                for (String pkg : packages) {
+                    final Bundle launcherExtras = pmi.getSuspendedPackageLauncherExtras(pkg,
+                            user.getIdentifier());
+                    if (launcherExtras != null) {
+                        packagesWithExtras.add(new Pair<>(pkg, launcherExtras));
+                    } else {
+                        packagesWithoutExtras.add(pkg);
+                    }
+                }
+                final String[] packagesNullExtras = packagesWithoutExtras.toArray(
+                        new String[packagesWithoutExtras.size()]);
                 final int n = mListeners.beginBroadcast();
                 try {
                     for (int i = 0; i < n; i++) {
@@ -1033,7 +1048,13 @@
                         BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
                         if (!isEnabledProfileOf(cookie.user, user, "onPackagesSuspended")) continue;
                         try {
-                            listener.onPackagesSuspended(user, packages, launcherExtras);
+                            listener.onPackagesSuspended(user, packagesNullExtras, null);
+                            for (int idx = 0; idx < packagesWithExtras.size(); idx++) {
+                                Pair<String, Bundle> packageExtraPair = packagesWithExtras.get(idx);
+                                listener.onPackagesSuspended(user,
+                                        new String[]{packageExtraPair.first},
+                                        packageExtraPair.second);
+                            }
                         } catch (RemoteException re) {
                             Slog.d(TAG, "Callback failed ", re);
                         }
@@ -1041,8 +1062,6 @@
                 } finally {
                     mListeners.finishBroadcast();
                 }
-
-                super.onPackagesSuspended(packages, launcherExtras);
             }
 
             @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d07e2d2..86340d4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -371,7 +371,6 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
-import java.util.function.Predicate;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -12448,14 +12447,10 @@
     }
 
     private void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
-            boolean suspended, PersistableBundle launcherExtras) {
+            boolean suspended) {
         final Bundle extras = new Bundle(3);
         extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
         extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
-        if (launcherExtras != null) {
-            extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
-                    new Bundle(launcherExtras.deepCopy()));
-        }
         sendPackageBroadcast(
                 suspended ? Intent.ACTION_PACKAGES_SUSPENDED
                         : Intent.ACTION_PACKAGES_UNSUSPENDED,
@@ -12720,8 +12715,6 @@
             if (ownerUid == callingUid) {
                 return;
             }
-            throw new UnsupportedOperationException("Cannot suspend/unsuspend packages. User "
-                    + userId + " has an active DO or PO");
         }
 
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
@@ -12729,6 +12722,7 @@
 
         final int packageUid = getPackageUid(callingPackage, 0, userId);
         final boolean allowedPackageUid = packageUid == callingUid;
+        // TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
         final boolean allowedShell = callingUid == SHELL_UID
                 && UserHandle.isSameApp(packageUid, callingUid);
 
@@ -12779,20 +12773,27 @@
                 unactionedPackages.add(packageName);
                 continue;
             }
+            boolean packageUnsuspended;
             synchronized (mLock) {
-                pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
-                        launcherExtras, userId);
+                if (suspended) {
+                    pkgSetting.addOrUpdateSuspension(callingPackage, dialogInfo, appExtras,
+                            launcherExtras, userId);
+                } else {
+                    pkgSetting.removeSuspension(callingPackage, userId);
+                }
+                packageUnsuspended = !suspended && !pkgSetting.getSuspended(userId);
             }
-            changedPackagesList.add(packageName);
-            changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+            if (suspended || packageUnsuspended) {
+                changedPackagesList.add(packageName);
+                changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+            }
         }
 
         if (!changedPackagesList.isEmpty()) {
             final String[] changedPackages = changedPackagesList.toArray(
                     new String[changedPackagesList.size()]);
-            sendPackagesSuspendedForUser(
-                    changedPackages, changedUids.toArray(), userId, suspended, launcherExtras);
-            sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, appExtras, userId);
+            sendPackagesSuspendedForUser(changedPackages, changedUids.toArray(), userId, suspended);
+            sendMyPackageSuspendedOrUnsuspended(changedPackages, suspended, userId);
             synchronized (mLock) {
                 scheduleWritePackageRestrictionsLocked(userId);
             }
@@ -12801,38 +12802,40 @@
     }
 
     @Override
-    public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId) {
+    public Bundle getSuspendedPackageAppExtras(String packageName, int userId) {
         final int callingUid = Binder.getCallingUid();
         if (getPackageUid(packageName, 0, userId) != callingUid) {
             throw new SecurityException("Calling package " + packageName
                     + " does not belong to calling uid " + callingUid);
         }
+        return getSuspendedPackageAppExtrasInternal(packageName, userId);
+    }
+
+    private Bundle getSuspendedPackageAppExtrasInternal(String packageName, int userId) {
         synchronized (mLock) {
             final PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null || shouldFilterApplicationLocked(ps, callingUid, userId)) {
+            if (ps == null) {
                 throw new IllegalArgumentException("Unknown target package: " + packageName);
             }
-            final PackageUserState packageUserState = ps.readUserState(userId);
-            if (packageUserState.suspended) {
-                return packageUserState.suspendedAppExtras;
+            final PackageUserState pus = ps.readUserState(userId);
+            final Bundle allExtras = new Bundle();
+            if (pus.suspended) {
+                for (int i = 0; i < pus.suspendParams.size(); i++) {
+                    final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i);
+                    if (params != null && params.appExtras != null) {
+                        allExtras.putAll(params.appExtras);
+                    }
+                }
             }
-            return null;
+            return (allExtras.size() > 0) ? allExtras : null;
         }
     }
 
     private void sendMyPackageSuspendedOrUnsuspended(String[] affectedPackages, boolean suspended,
-            PersistableBundle appExtras, int userId) {
-        final String action;
-        final Bundle intentExtras = new Bundle();
-        if (suspended) {
-            action = Intent.ACTION_MY_PACKAGE_SUSPENDED;
-            if (appExtras != null) {
-                final Bundle bundledAppExtras = new Bundle(appExtras.deepCopy());
-                intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, bundledAppExtras);
-            }
-        } else {
-            action = Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
-        }
+            int userId) {
+        final String action = suspended
+                ? Intent.ACTION_MY_PACKAGE_SUSPENDED
+                : Intent.ACTION_MY_PACKAGE_UNSUSPENDED;
         mHandler.post(() -> {
             try {
                 final IActivityManager am = ActivityManager.getService();
@@ -12843,6 +12846,16 @@
                 }
                 final int[] targetUserIds = new int[] {userId};
                 for (String packageName : affectedPackages) {
+                    final Bundle appExtras = suspended
+                            ? getSuspendedPackageAppExtrasInternal(packageName, userId)
+                            : null;
+                    final Bundle intentExtras;
+                    if (appExtras != null) {
+                        intentExtras = new Bundle(1);
+                        intentExtras.putBundle(Intent.EXTRA_SUSPENDED_PACKAGE_EXTRAS, appExtras);
+                    } else {
+                        intentExtras = null;
+                    }
                     doSendBroadcast(am, action, null, intentExtras,
                             Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, packageName, null,
                             targetUserIds, false);
@@ -12875,57 +12888,32 @@
      * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
      * synchronously
      *
-     * @param packageName The package holding {@link Manifest.permission#SUSPEND_APPS} permission
-     * @param affectedUser The user for which the changes are taking place.
+     * @param suspendingPackage The suspending package
+     * @param userId The user for which the changes are taking place.
      */
-    void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
-        final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? mUserManager.getUserIds()
-                : new int[] {affectedUser};
-        for (int userId : userIds) {
-            unsuspendForSuspendingPackages(packageName::equals, userId);
-        }
-    }
-
-    /**
-     * Immediately unsuspends any packages in the given users not suspended by the platform or root.
-     * To be called when a profile owner or a device owner is added.
-     *
-     * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
-     * synchronously
-     *
-     * @param userIds The users for which to unsuspend packages
-     */
-    void unsuspendForNonSystemSuspendingPackages(ArraySet<Integer> userIds) {
-        final int sz = userIds.size();
-        for (int i = 0; i < sz; i++) {
-            unsuspendForSuspendingPackages(
-                    (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
-                    userIds.valueAt(i));
-        }
-    }
-
-    private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
-        final List<String> affectedPackages = new ArrayList<>();
-        final IntArray affectedUids = new IntArray();
+    private void unsuspendForSuspendingPackage(String suspendingPackage, int userId) {
+        final List<String> unsuspendedPackages = new ArrayList<>();
+        final IntArray unsuspendedUids = new IntArray();
         synchronized (mLock) {
             for (PackageSetting ps : mSettings.mPackages.values()) {
                 final PackageUserState pus = ps.readUserState(userId);
-                if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
-                    ps.setSuspended(false, null, null, null, null, userId);
-                    affectedPackages.add(ps.name);
-                    affectedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+                if (pus.suspended) {
+                    ps.removeSuspension(suspendingPackage, userId);
+                    if (!ps.getSuspended(userId)) {
+                        unsuspendedPackages.add(ps.name);
+                        unsuspendedUids.add(UserHandle.getUid(userId, ps.getAppId()));
+                    }
                 }
             }
         }
-        if (!affectedPackages.isEmpty()) {
-            final String[] packageArray = affectedPackages.toArray(
-                    new String[affectedPackages.size()]);
-            sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
-            sendPackagesSuspendedForUser(
-                    packageArray, affectedUids.toArray(), userId, false, null);
-            // Write package restrictions immediately to avoid an inconsistent state.
-            mSettings.writePackageRestrictionsLPr(userId);
+        if (!unsuspendedPackages.isEmpty()) {
+            final String[] packageArray = unsuspendedPackages.toArray(
+                    new String[unsuspendedPackages.size()]);
+            sendMyPackageSuspendedOrUnsuspended(packageArray, false, userId);
+            sendPackagesSuspendedForUser(packageArray, unsuspendedUids.toArray(), userId, false);
         }
+        // Write package restrictions immediately to avoid an inconsistent state.
+        mSettings.writePackageRestrictionsLPr(userId);
     }
 
     @Override
@@ -18437,10 +18425,7 @@
                     false /*hidden*/,
                     0 /*distractionFlags*/,
                     false /*suspended*/,
-                    null /*suspendingPackage*/,
-                    null /*dialogInfo*/,
-                    null /*suspendedAppExtras*/,
-                    null /*suspendedLauncherExtras*/,
+                    null /*suspendParams*/,
                     false /*instantApp*/,
                     false /*virtualPreload*/,
                     null /*lastDisableAppCaller*/,
@@ -19995,7 +19980,11 @@
             }
         }
         synchronized (mLock) {
-            scheduleWritePackageRestrictionsLocked(userId);
+            if ((flags & PackageManager.SYNCHRONOUS) != 0) {
+                flushPackageRestrictionsAsUserInternalLocked(userId);
+            } else {
+                scheduleWritePackageRestrictionsLocked(userId);
+            }
             updateSequenceNumberLP(pkgSetting, new int[] { userId });
             final long callingId = Binder.clearCallingIdentity();
             try {
@@ -20056,11 +20045,16 @@
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
                 false /* checkShell */, "flushPackageRestrictions");
         synchronized (mLock) {
-            mSettings.writePackageRestrictionsLPr(userId);
-            mDirtyUsers.remove(userId);
-            if (mDirtyUsers.isEmpty()) {
-                mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
-            }
+            flushPackageRestrictionsAsUserInternalLocked(userId);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void flushPackageRestrictionsAsUserInternalLocked(int userId) {
+        mSettings.writePackageRestrictionsLPr(userId);
+        mDirtyUsers.remove(userId);
+        if (mDirtyUsers.isEmpty()) {
+            mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
         }
     }
 
@@ -20270,7 +20264,7 @@
                     mInjector.getPermissionPolicyInternal();
             permissionPolicyInternal.setOnInitializedCallback(userId -> {
                 // The SDK updated case is already handled when we run during the ctor.
-                synchronized (mPackages) {
+                synchronized (mLock) {
                     mPermissionManager.updateAllPermissions(
                             StorageManager.UUID_PRIVATE_INTERNAL, false);
                 }
@@ -22951,11 +22945,21 @@
         public Bundle getSuspendedPackageLauncherExtras(String packageName, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(packageName);
-                PersistableBundle launcherExtras = null;
+                final Bundle allExtras = new Bundle();
                 if (ps != null) {
-                    launcherExtras = ps.readUserState(userId).suspendedLauncherExtras;
+                    final PackageUserState pus = ps.readUserState(userId);
+                    if (pus.suspended) {
+                        for (int i = 0; i < pus.suspendParams.size(); i++) {
+                            final PackageUserState.SuspendParams params =
+                                    pus.suspendParams.valueAt(i);
+                            if (params != null && params.launcherExtras != null) {
+                                allExtras.putAll(params.launcherExtras);
+                            }
+                        }
+                    }
+
                 }
-                return (launcherExtras != null) ? new Bundle(launcherExtras.deepCopy()) : null;
+                return (allExtras.size() > 0) ? allExtras : null;
             }
         }
 
@@ -22971,16 +22975,38 @@
         public String getSuspendingPackage(String suspendedPackage, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
-                return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
+                if (ps != null) {
+                    final PackageUserState pus = ps.readUserState(userId);
+                    if (pus.suspended) {
+                        String suspendingPackage = null;
+                        for (int i = 0; i < pus.suspendParams.size(); i++) {
+                            suspendingPackage = pus.suspendParams.keyAt(i);
+                            if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+                                return suspendingPackage;
+                            }
+                        }
+                        return suspendingPackage;
+                    }
+                }
+                return null;
             }
         }
 
         @Override
-        public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId) {
+        public SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
+                String suspendingPackage, int userId) {
             synchronized (mLock) {
                 final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
-                return (ps != null) ? ps.readUserState(userId).dialogInfo : null;
+                if (ps != null) {
+                    final PackageUserState pus = ps.readUserState(userId);
+                    if (pus.suspended) {
+                        final PackageUserState.SuspendParams suspendParams =
+                                pus.suspendParams.get(suspendingPackage);
+                        return (suspendParams != null) ? suspendParams.dialogInfo : null;
+                    }
+                }
             }
+            return null;
         }
 
         @Override
@@ -23057,7 +23083,6 @@
                     usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
                 }
             }
-            unsuspendForNonSystemSuspendingPackages(usersWithPoOrDo);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3f32f3d..1c1c947 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -751,7 +751,7 @@
                     (!listThirdParty || !isSystem) &&
                     (!listApexOnly || isApex)) {
                 pw.print("package:");
-                if (showSourceDir && !isApex) {
+                if (showSourceDir) {
                     pw.print(info.applicationInfo.sourceDir);
                     pw.print("=");
                 }
@@ -2068,7 +2068,9 @@
                 userId = UserHandle.USER_SYSTEM;
             }
             mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
-                    appExtras, launcherExtras, info, callingPackage, userId);
+                    ((appExtras.size() > 0) ? appExtras : null),
+                    ((launcherExtras.size() > 0) ? launcherExtras : null),
+                    info, callingPackage, userId);
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
@@ -2413,6 +2415,7 @@
         int userId = -1;
         int flags = 0;
         String opt;
+        boolean preCreateOnly = false;
         while ((opt = getNextOption()) != null) {
             if ("--profileOf".equals(opt)) {
                 userId = UserHandle.parseUserArg(getNextArgRequired());
@@ -2426,6 +2429,8 @@
                 flags |= UserInfo.FLAG_GUEST;
             } else if ("--demo".equals(opt)) {
                 flags |= UserInfo.FLAG_DEMO;
+            } else if ("--pre-create-only".equals(opt)) {
+                preCreateOnly = true;
             } else {
                 getErrPrintWriter().println("Error: unknown option " + opt);
                 return 1;
@@ -2449,7 +2454,7 @@
             accm.addSharedAccountsFromParentUser(parentUserId, userId,
                     (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
         } else if (userId < 0) {
-            info = um.createUser(name, flags);
+            info = preCreateOnly ? um.preCreateUser(flags) : um.createUser(name, flags);
         } else {
             info = um.createProfileForUser(name, flags, userId, null);
         }
@@ -3362,8 +3367,11 @@
         pw.println("  trim-caches DESIRED_FREE_SPACE [internal|UUID]");
         pw.println("    Trim cache files to reach the given free space.");
         pw.println("");
+        pw.println("  list users");
+        pw.println("    Lists the current users.");
+        pw.println("");
         pw.println("  create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral]");
-        pw.println("      [--guest] USER_NAME");
+        pw.println("      [--guest] [--pre-create-only] USER_NAME");
         pw.println("    Create a new user with the given USER_NAME, printing the new user identifier");
         pw.println("    of the user.");
         pw.println("");
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 029673f..0da6b54 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -29,6 +29,7 @@
 import android.content.pm.SuspendDialogInfo;
 import android.os.PersistableBundle;
 import android.service.pm.PackageProto;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
@@ -405,14 +406,28 @@
         return readUserState(userId).suspended;
     }
 
-    void setSuspended(boolean suspended, String suspendingPackage, SuspendDialogInfo dialogInfo,
+    void addOrUpdateSuspension(String suspendingPackage, SuspendDialogInfo dialogInfo,
             PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
         final PackageUserState existingUserState = modifyUserState(userId);
-        existingUserState.suspended = suspended;
-        existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
-        existingUserState.dialogInfo = suspended ? dialogInfo : null;
-        existingUserState.suspendedAppExtras = suspended ? appExtras : null;
-        existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
+        final PackageUserState.SuspendParams newSuspendParams =
+                PackageUserState.SuspendParams.getInstanceOrNull(dialogInfo, appExtras,
+                        launcherExtras);
+        if (existingUserState.suspendParams == null) {
+            existingUserState.suspendParams = new ArrayMap<>();
+        }
+        existingUserState.suspendParams.put(suspendingPackage, newSuspendParams);
+        existingUserState.suspended = true;
+    }
+
+    void removeSuspension(String suspendingPackage, int userId) {
+        final PackageUserState existingUserState = modifyUserState(userId);
+        if (existingUserState.suspendParams != null) {
+            existingUserState.suspendParams.remove(suspendingPackage);
+            if (existingUserState.suspendParams.size() == 0) {
+                existingUserState.suspendParams = null;
+            }
+        }
+        existingUserState.suspended = (existingUserState.suspendParams != null);
     }
 
     public boolean getInstantApp(int userId) {
@@ -433,9 +448,7 @@
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
             boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
-            String suspendingPackage,
-            SuspendDialogInfo dialogInfo, PersistableBundle suspendedAppExtras,
-            PersistableBundle suspendedLauncherExtras, boolean instantApp,
+            ArrayMap<String, PackageUserState.SuspendParams> suspendParams, boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
             int domainVerifState, int linkGeneration, int installReason,
@@ -449,10 +462,7 @@
         state.hidden = hidden;
         state.distractionFlags = distractionFlags;
         state.suspended = suspended;
-        state.suspendingPackage = suspendingPackage;
-        state.dialogInfo = dialogInfo;
-        state.suspendedAppExtras = suspendedAppExtras;
-        state.suspendedLauncherExtras = suspendedLauncherExtras;
+        state.suspendParams = suspendParams;
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
@@ -467,9 +477,8 @@
     void setUserState(int userId, PackageUserState otherState) {
         setUserState(userId, otherState.ceDataInode, otherState.enabled, otherState.installed,
                 otherState.stopped, otherState.notLaunched, otherState.hidden,
-                otherState.distractionFlags, otherState.suspended, otherState.suspendingPackage,
-                otherState.dialogInfo, otherState.suspendedAppExtras,
-                otherState.suspendedLauncherExtras, otherState.instantApp,
+                otherState.distractionFlags, otherState.suspended, otherState.suspendParams,
+                otherState.instantApp,
                 otherState.virtualPreload, otherState.lastDisableAppCaller,
                 otherState.enabledComponents, otherState.disabledComponents,
                 otherState.domainVerificationStatus, otherState.appLinkGeneration,
@@ -633,7 +642,10 @@
             proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags);
             proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
             if (state.suspended) {
-                proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, state.suspendingPackage);
+                for (int j = 0; j < state.suspendParams.size(); j++) {
+                    proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
+                            state.suspendParams.keyAt(j));
+                }
             }
             proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.stopped);
             proto.write(PackageProto.UserInfoProto.IS_LAUNCHED, !state.notLaunched);
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index b94047e..b464988 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -78,6 +78,13 @@
         sMacPermissions.add(new File(
             Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"));
 
+        // SystemExt mac permissions (optional).
+        final File systemExtMacPermission = new File(
+                Environment.getSystemExtDirectory(), "/etc/selinux/system_ext_mac_permissions.xml");
+        if (systemExtMacPermission.exists()) {
+            sMacPermissions.add(systemExtMacPermission);
+        }
+
         // Product mac permissions (optional).
         final File productMacPermission = new File(
                 Environment.getProductDirectory(), "/etc/selinux/product_mac_permissions.xml");
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 4349ea7..0db6e79 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -205,9 +205,22 @@
     private static final String TAG_DEFAULT_BROWSER = "default-browser";
     private static final String TAG_DEFAULT_DIALER = "default-dialer";
     private static final String TAG_VERSION = "version";
+    /**
+     * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+     */
+    @Deprecated
     private static final String TAG_SUSPENDED_DIALOG_INFO = "suspended-dialog-info";
+    /**
+     * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+     */
+    @Deprecated
     private static final String TAG_SUSPENDED_APP_EXTRAS = "suspended-app-extras";
+    /**
+     * @deprecated Moved to {@link android.content.pm.PackageUserState.SuspendParams}
+     */
+    @Deprecated
     private static final String TAG_SUSPENDED_LAUNCHER_EXTRAS = "suspended-launcher-extras";
+    private static final String TAG_SUSPEND_PARAMS = "suspend-params";
 
     public static final String ATTR_NAME = "name";
     public static final String ATTR_PACKAGE = "package";
@@ -660,10 +673,7 @@
                                 false /*hidden*/,
                                 0 /*distractionFlags*/,
                                 false /*suspended*/,
-                                null /*suspendingPackage*/,
-                                null /*dialogInfo*/,
-                                null /*suspendedAppExtras*/,
-                                null /*suspendedLauncherExtras*/,
+                                null /*suspendParams*/,
                                 instantApp,
                                 virtualPreload,
                                 null /*lastDisableAppCaller*/,
@@ -1550,10 +1560,7 @@
                                 false /*hidden*/,
                                 0 /*distractionFlags*/,
                                 false /*suspended*/,
-                                null /*suspendingPackage*/,
-                                null /*dialogInfo*/,
-                                null /*suspendedAppExtras*/,
-                                null /*suspendedLauncherExtras*/,
+                                null /*suspendParams*/,
                                 false /*instantApp*/,
                                 false /*virtualPreload*/,
                                 null /*lastDisableAppCaller*/,
@@ -1628,12 +1635,12 @@
                             ATTR_DISTRACTION_FLAGS, 0);
                     final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
                             false);
-                    String suspendingPackage = parser.getAttributeValue(null,
+                    String oldSuspendingPackage = parser.getAttributeValue(null,
                             ATTR_SUSPENDING_PACKAGE);
                     final String dialogMessage = parser.getAttributeValue(null,
                             ATTR_SUSPEND_DIALOG_MESSAGE);
-                    if (suspended && suspendingPackage == null) {
-                        suspendingPackage = PLATFORM_PACKAGE_NAME;
+                    if (suspended && oldSuspendingPackage == null) {
+                        oldSuspendingPackage = PLATFORM_PACKAGE_NAME;
                     }
 
                     final boolean blockUninstall = XmlUtils.readBooleanAttribute(parser,
@@ -1663,9 +1670,10 @@
                     ArraySet<String> disabledComponents = null;
                     PersistableBundle suspendedAppExtras = null;
                     PersistableBundle suspendedLauncherExtras = null;
-                    SuspendDialogInfo suspendDialogInfo = null;
+                    SuspendDialogInfo oldSuspendDialogInfo = null;
 
                     int packageDepth = parser.getDepth();
+                    ArrayMap<String, PackageUserState.SuspendParams> suspendParamsMap = null;
                     while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
                             && (type != XmlPullParser.END_TAG
                             || parser.getDepth() > packageDepth)) {
@@ -1687,26 +1695,48 @@
                                 suspendedLauncherExtras = PersistableBundle.restoreFromXml(parser);
                                 break;
                             case TAG_SUSPENDED_DIALOG_INFO:
-                                suspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
+                                oldSuspendDialogInfo = SuspendDialogInfo.restoreFromXml(parser);
+                                break;
+                            case TAG_SUSPEND_PARAMS:
+                                final String suspendingPackage = parser.getAttributeValue(null,
+                                        ATTR_SUSPENDING_PACKAGE);
+                                if (suspendingPackage == null) {
+                                    Slog.wtf(TAG, "No suspendingPackage found inside tag "
+                                            + TAG_SUSPEND_PARAMS);
+                                    continue;
+                                }
+                                if (suspendParamsMap == null) {
+                                    suspendParamsMap = new ArrayMap<>();
+                                }
+                                suspendParamsMap.put(suspendingPackage,
+                                        PackageUserState.SuspendParams.restoreFromXml(parser));
                                 break;
                             default:
                                 Slog.wtf(TAG, "Unknown tag " + parser.getName() + " under tag "
                                         + TAG_PACKAGE);
                         }
                     }
-                    if (suspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) {
-                        suspendDialogInfo = new SuspendDialogInfo.Builder()
+                    if (oldSuspendDialogInfo == null && !TextUtils.isEmpty(dialogMessage)) {
+                        oldSuspendDialogInfo = new SuspendDialogInfo.Builder()
                                 .setMessage(dialogMessage)
                                 .build();
                     }
+                    if (suspended && suspendParamsMap == null) {
+                        final PackageUserState.SuspendParams suspendParams =
+                                PackageUserState.SuspendParams.getInstanceOrNull(
+                                        oldSuspendDialogInfo,
+                                        suspendedAppExtras,
+                                        suspendedLauncherExtras);
+                        suspendParamsMap = new ArrayMap<>();
+                        suspendParamsMap.put(oldSuspendingPackage, suspendParams);
+                    }
 
                     if (blockUninstall) {
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, distractionFlags, suspended, suspendingPackage,
-                            suspendDialogInfo,
-                            suspendedAppExtras, suspendedLauncherExtras, instantApp, virtualPreload,
+                            hidden, distractionFlags, suspended, suspendParamsMap,
+                            instantApp, virtualPreload,
                             enabledCaller, enabledComponents, disabledComponents, verifState,
                             linkGeneration, installReason, harmfulAppWarning);
                 } else if (tagName.equals("preferred-activities")) {
@@ -2006,35 +2036,6 @@
                 }
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
-                    if (ustate.suspendingPackage != null) {
-                        serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
-                                ustate.suspendingPackage);
-                    }
-                    if (ustate.dialogInfo != null) {
-                        serializer.startTag(null, TAG_SUSPENDED_DIALOG_INFO);
-                        ustate.dialogInfo.saveToXml(serializer);
-                        serializer.endTag(null, TAG_SUSPENDED_DIALOG_INFO);
-                    }
-                    if (ustate.suspendedAppExtras != null) {
-                        serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
-                        try {
-                            ustate.suspendedAppExtras.saveToXml(serializer);
-                        } catch (XmlPullParserException xmle) {
-                            Slog.wtf(TAG, "Exception while trying to write suspendedAppExtras for "
-                                    + pkg + ". Will be lost on reboot", xmle);
-                        }
-                        serializer.endTag(null, TAG_SUSPENDED_APP_EXTRAS);
-                    }
-                    if (ustate.suspendedLauncherExtras != null) {
-                        serializer.startTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
-                        try {
-                            ustate.suspendedLauncherExtras.saveToXml(serializer);
-                        } catch (XmlPullParserException xmle) {
-                            Slog.wtf(TAG, "Exception while trying to write suspendedLauncherExtras"
-                                    + " for " + pkg + ". Will be lost on reboot", xmle);
-                        }
-                        serializer.endTag(null, TAG_SUSPENDED_LAUNCHER_EXTRAS);
-                    }
                 }
                 if (ustate.instantApp) {
                     serializer.attribute(null, ATTR_INSTANT_APP, "true");
@@ -2067,6 +2068,19 @@
                     serializer.attribute(null, ATTR_HARMFUL_APP_WARNING,
                             ustate.harmfulAppWarning);
                 }
+                if (ustate.suspended) {
+                    for (int i = 0; i < ustate.suspendParams.size(); i++) {
+                        final String suspendingPackage = ustate.suspendParams.keyAt(i);
+                        serializer.startTag(null, TAG_SUSPEND_PARAMS);
+                        serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, suspendingPackage);
+                        final PackageUserState.SuspendParams params =
+                                ustate.suspendParams.valueAt(i);
+                        if (params != null) {
+                            params.saveToXml(serializer);
+                        }
+                        serializer.endTag(null, TAG_SUSPEND_PARAMS);
+                    }
+                }
                 if (!ArrayUtils.isEmpty(ustate.enabledComponents)) {
                     serializer.startTag(null, TAG_ENABLED_COMPONENTS);
                     for (final String name : ustate.enabledComponents) {
@@ -4766,13 +4780,6 @@
             pw.print(ps.getHidden(user.id));
             pw.print(" suspended=");
             pw.print(ps.getSuspended(user.id));
-            if (ps.getSuspended(user.id)) {
-                final PackageUserState pus = ps.readUserState(user.id);
-                pw.print(" suspendingPackage=");
-                pw.print(pus.suspendingPackage);
-                pw.print(" dialogInfo=");
-                pw.print(pus.dialogInfo);
-            }
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
             pw.print(" notLaunched=");
@@ -4784,6 +4791,23 @@
             pw.print(" virtual=");
             pw.println(ps.getVirtulalPreload(user.id));
 
+            if (ps.getSuspended(user.id)) {
+                pw.print(prefix);
+                pw.println("  Suspend params:");
+                final PackageUserState pus = ps.readUserState(user.id);
+                for (int i = 0; i < pus.suspendParams.size(); i++) {
+                    pw.print(prefix);
+                    pw.print("    suspendingPackage=");
+                    pw.print(pus.suspendParams.keyAt(i));
+                    final PackageUserState.SuspendParams params = pus.suspendParams.valueAt(i);
+                    if (params != null) {
+                        pw.print(" dialogInfo=");
+                        pw.print(params.dialogInfo);
+                    }
+                    pw.println();
+                }
+            }
+
             String[] overlayPaths = ps.getOverlayPaths(user.id);
             if (overlayPaths != null && overlayPaths.length > 0) {
                 pw.print(prefix); pw.println("  overlay paths:");
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5f86708..ca273ba 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -41,6 +41,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.os.Binder;
@@ -158,6 +159,7 @@
     private static final String ATTR_SERIAL_NO = "serialNumber";
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
+    private static final String ATTR_PRE_CREATED = "preCreated";
     private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
     private static final String ATTR_USER_VERSION = "version";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
@@ -597,7 +599,8 @@
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
                 UserInfo ui = mUsers.valueAt(i).info;
-                if ((ui.partial || ui.guestToRemove || ui.isEphemeral()) && i != 0) {
+                if ((ui.partial || ui.guestToRemove || (ui.isEphemeral() && !ui.preCreated))
+                        && i != 0) {
                     partials.add(ui);
                     addRemovingUserIdLocked(ui.id);
                     ui.partial = true;
@@ -662,18 +665,23 @@
 
     @Override
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
+        return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */ true);
+    }
+
+    private @NonNull List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying,
+            boolean excludePreCreated) {
         checkManageOrCreateUsersPermission("query users");
         synchronized (mUsersLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             final int userSize = mUsers.size();
             for (int i = 0; i < userSize; i++) {
                 UserInfo ui = mUsers.valueAt(i).info;
-                if (ui.partial) {
+                if ((excludePartial && ui.partial)
+                        || (excludeDying && mRemovingUserIds.get(ui.id))
+                        || (excludePreCreated && ui.preCreated)) {
                     continue;
                 }
-                if (!excludeDying || !mRemovingUserIds.get(ui.id)) {
-                    users.add(userWithName(ui));
-                }
+                users.add(userWithName(ui));
             }
             return users;
         }
@@ -1196,7 +1204,7 @@
 
     private void checkManageOrInteractPermIfCallerInOtherProfileGroup(@UserIdInt int userId,
             String name) {
-        int callingUserId = UserHandle.getCallingUserId();
+        final int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId == userId || isSameProfileGroupNoChecks(callingUserId, userId) ||
                 hasManageUsersPermission()) {
             return;
@@ -1210,7 +1218,7 @@
 
     @Override
     public boolean isDemoUser(@UserIdInt int userId) {
-        int callingUserId = UserHandle.getCallingUserId();
+        final int callingUserId = UserHandle.getCallingUserId();
         if (callingUserId != userId && !hasManageUsersPermission()) {
             throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId
                     + " is a demo user");
@@ -1222,6 +1230,19 @@
     }
 
     @Override
+    public boolean isPreCreated(@UserIdInt int userId) {
+        final int callingUserId = UserHandle.getCallingUserId();
+        if (callingUserId != userId && !hasManageUsersPermission()) {
+            throw new SecurityException("You need MANAGE_USERS permission to query if u=" + userId
+                    + " is pre-created");
+        }
+        synchronized (mUsersLock) {
+            UserInfo userInfo = getUserInfoLU(userId);
+            return userInfo != null && userInfo.preCreated;
+        }
+    }
+
+    @Override
     public boolean isRestricted() {
         synchronized (mUsersLock) {
             return getUserInfoLU(UserHandle.getCallingUserId()).isRestricted();
@@ -1871,7 +1892,7 @@
         // Skip over users being removed
         for (int i = 0; i < totalUserCount; i++) {
             UserInfo user = mUsers.valueAt(i).info;
-            if (!mRemovingUserIds.get(user.id) && !user.isGuest()) {
+            if (!mRemovingUserIds.get(user.id) && !user.isGuest() && !user.preCreated) {
                 aliveUserCount++;
             }
         }
@@ -2362,6 +2383,9 @@
         if (userInfo.partial) {
             serializer.attribute(null, ATTR_PARTIAL, "true");
         }
+        if (userInfo.preCreated) {
+            serializer.attribute(null, ATTR_PRE_CREATED, "true");
+        }
         if (userInfo.guestToRemove) {
             serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
         }
@@ -2518,6 +2542,7 @@
         int profileBadge = 0;
         int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
         boolean partial = false;
+        boolean preCreated = false;
         boolean guestToRemove = false;
         boolean persistSeedData = false;
         String seedAccountName = null;
@@ -2562,6 +2587,10 @@
             if ("true".equals(valueString)) {
                 partial = true;
             }
+            valueString = parser.getAttributeValue(null, ATTR_PRE_CREATED);
+            if ("true".equals(valueString)) {
+                preCreated = true;
+            }
             valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
             if ("true".equals(valueString)) {
                 guestToRemove = true;
@@ -2615,6 +2644,7 @@
         userInfo.lastLoggedInTime = lastLoggedInTime;
         userInfo.lastLoggedInFingerprint = lastLoggedInFingerprint;
         userInfo.partial = partial;
+        userInfo.preCreated = preCreated;
         userInfo.guestToRemove = guestToRemove;
         userInfo.profileGroupId = profileGroupId;
         userInfo.profileBadge = profileBadge;
@@ -2686,7 +2716,8 @@
     public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags,
             @UserIdInt int userId, String[] disallowedPackages) {
         checkManageOrCreateUsersPermission(flags);
-        return createUserInternalUnchecked(name, flags, userId, disallowedPackages);
+        return createUserInternalUnchecked(name, flags, userId, /* preCreate= */ false,
+                disallowedPackages);
     }
 
     @Override
@@ -2701,12 +2732,25 @@
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
-    private UserInfo createUserInternal(String name, int flags, int parentId) {
+    @Override
+    public UserInfo preCreateUser(int flags) {
+        checkManageOrCreateUsersPermission(flags);
+
+        Preconditions.checkArgument(!UserInfo.isManagedProfile(flags),
+                "cannot pre-create managed profiles");
+
+        return createUserInternalUnchecked(/* name= */ null, flags,
+                /* parentId= */ UserHandle.USER_NULL, /* preCreate= */ true,
+                /* disallowedPackages= */ null);
+    }
+
+    private UserInfo createUserInternal(@Nullable String name, @UserInfoFlag int flags,
+            @UserIdInt int parentId) {
         return createUserInternal(name, flags, parentId, null);
     }
 
-    private UserInfo createUserInternal(String name, int flags, int parentId,
-            String[] disallowedPackages) {
+    private UserInfo createUserInternal(@Nullable String name, @UserInfoFlag int flags,
+            @UserIdInt int parentId, @Nullable String[] disallowedPackages) {
         String restriction = ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0)
                 ? UserManager.DISALLOW_ADD_MANAGED_PROFILE
                 : UserManager.DISALLOW_ADD_USER;
@@ -2714,21 +2758,56 @@
             Log.w(LOG_TAG, "Cannot add user. " + restriction + " is enabled.");
             return null;
         }
-        return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
+        return createUserInternalUnchecked(name, flags, parentId, /* preCreate= */ false,
+                disallowedPackages);
     }
 
-    private UserInfo createUserInternalUnchecked(@Nullable String name, int flags,
-            int parentId, @Nullable String[] disallowedPackages) {
-        TimingsTraceAndSlog t = new TimingsTraceAndSlog();
-        t.traceBegin("createUser");
-        UserInfo userInfo =
-                createUserInternalUncheckedNoTracing(name, flags, parentId, disallowedPackages, t);
-        t.traceEnd();
-        return userInfo;
+    private UserInfo createUserInternalUnchecked(@Nullable String name, @UserInfoFlag int flags,
+            @UserIdInt int parentId, boolean preCreate,
+            @Nullable String[] disallowedPackages) {
+        final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
+        t.traceBegin("createUser-" + flags);
+        try {
+            return createUserInternalUncheckedNoTracing(name, flags, parentId, preCreate,
+                disallowedPackages, t);
+        } finally {
+            t.traceEnd();
+        }
     }
 
-    private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name, int flags,
-            int parentId, @Nullable String[] disallowedPackages, @NonNull TimingsTraceAndSlog t) {
+    private UserInfo createUserInternalUncheckedNoTracing(@Nullable String name,
+            @UserInfoFlag int flags, @UserIdInt int parentId, boolean preCreate,
+            @Nullable String[] disallowedPackages, @NonNull TimingsTraceAndSlog t) {
+
+        // First try to use a pre-created user (if available).
+        // NOTE: currently we don't support pre-created managed profiles
+        if (!preCreate && (parentId < 0 && !UserInfo.isManagedProfile(flags))) {
+            final UserData preCreatedUserData;
+            synchronized (mUsersLock) {
+                preCreatedUserData = getPreCreatedUserLU(flags);
+            }
+            if (preCreatedUserData != null) {
+                final UserInfo preCreatedUser = preCreatedUserData.info;
+                Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " for flags + "
+                        + UserInfo.flagsToString(flags));
+                if (DBG) {
+                    Log.d(LOG_TAG, "pre-created user flags: "
+                            + UserInfo.flagsToString(preCreatedUser.flags)
+                            + " new-user flags: " + UserInfo.flagsToString(flags));
+                }
+                preCreatedUser.name = name;
+                preCreatedUser.preCreated = false;
+                preCreatedUser.creationTime = getCreationTime();
+
+                dispatchUserAddedIntent(preCreatedUser);
+
+                writeUserLP(preCreatedUserData);
+                writeUserListLP();
+
+                return preCreatedUser;
+            }
+        }
+
         DeviceStorageMonitorInternal dsm = LocalServices
                 .getService(DeviceStorageMonitorInternal.class);
         if (dsm.isMemoryLow()) {
@@ -2736,8 +2815,8 @@
             return null;
         }
 
-        final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
-        final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
+        final boolean isGuest = UserInfo.isGuest(flags);
+        final boolean isManagedProfile = UserInfo.isManagedProfile(flags);
         final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
         final boolean isDemo = (flags & UserInfo.FLAG_DEMO) != 0;
         final long ident = Binder.clearCallingIdentity();
@@ -2758,8 +2837,8 @@
                     return null;
                 }
                 if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
-                    // If we're not adding a guest/demo user or a managed profile and the limit has
-                    // been reached, cannot add a user.
+                    // If we're not adding a guest/demo user or a managed profile,
+                    // and the limit has been reached, cannot add a user.
                     Log.e(LOG_TAG, "Cannot add user. Maximum user limit is reached.");
                     return null;
                 }
@@ -2794,8 +2873,7 @@
 
                 userId = getNextAvailableId();
                 Environment.getUserSystemDirectory(userId).mkdirs();
-                boolean ephemeralGuests = Resources.getSystem()
-                        .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
+                boolean ephemeralGuests = areGuestUsersEphemeral();
 
                 synchronized (mUsersLock) {
                     // Add ephemeral flag to guests/users if required. Also inherit it from parent.
@@ -2806,9 +2884,9 @@
 
                     userInfo = new UserInfo(userId, name, null, flags);
                     userInfo.serialNumber = mNextSerialNumber++;
-                    long now = System.currentTimeMillis();
-                    userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
+                    userInfo.creationTime = getCreationTime();
                     userInfo.partial = true;
+                    userInfo.preCreated = preCreate;
                     userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
                     if (isManagedProfile && parentId != UserHandle.USER_NULL) {
                         userInfo.profileBadge = getFreeProfileBadgeLU(parentId);
@@ -2869,17 +2947,40 @@
 
             t.traceBegin("PM.onNewUserCreated");
             mPm.onNewUserCreated(userId);
-            t.traceEnd();
 
-            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
-            addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-            mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
-                    android.Manifest.permission.MANAGE_USERS);
-            MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED
-                    : (isDemo ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
+            if (preCreate) {
+                // Must start user (which will be stopped right away, through
+                // UserController.finishUserUnlockedCompleted) so services can properly
+                // intialize it.
+                // TODO(b/140750212): in the long-term, we should add a onCreateUser() callback
+                // on SystemService instead.
+                Slog.i(LOG_TAG, "starting pre-created user " + userInfo.toFullString());
+                final IActivityManager am = ActivityManager.getService();
+                try {
+                    am.startUserInBackground(userId);
+                } catch (RemoteException e) {
+                    Slog.w(LOG_TAG, "could not start pre-created user " + userId, e);
+                }
+            } else {
+                dispatchUserAddedIntent(userInfo);
+            }
+
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
+
+        // TODO(b/140750212): it's possible to reach "max users overflow" when the user is created
+        // "from scratch" (i.e., not from a pre-created user) and reaches the maximum number of
+        // users without counting the pre-created one. Then when the pre-created is converted, the
+        // "effective" number of max users is exceeds. Example:
+        // Max: 3 Current: 2 full (u0 and u10) + 1 pre-created (u11)
+        // Step 1: create(/* flags doesn't match u11 */): u12 is created, "effective max" is now 3
+        //         (u0, u10, u12) but "real" max is 4 (u0, u10, u11, u12)
+        // Step 2: create(/* flags match u11 */): u11 is converted, now "effective max" is also 4
+        //         (u0, u10, u11, u12)
+        // One way to avoid this issue is by removing a pre-created user from the pool when the
+        // "real" max exceeds the max here.
+
         return userInfo;
     }
 
@@ -2888,6 +2989,62 @@
         return mSystemPackageInstaller.installWhitelistedSystemPackages(isFirstBoot, isUpgrade);
     }
 
+    private long getCreationTime() {
+        final long now = System.currentTimeMillis();
+        return (now > EPOCH_PLUS_30_YEARS) ? now : 0;
+    }
+
+    private void dispatchUserAddedIntent(@NonNull UserInfo userInfo) {
+        Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+        addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
+        mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+                android.Manifest.permission.MANAGE_USERS);
+        MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED
+                : (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
+    }
+
+    private boolean areGuestUsersEphemeral() {
+        return Resources.getSystem()
+                .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);
+    }
+
+    /**
+     * Gets a pre-created user for the given flag.
+     *
+     * <p>Should be used only during user creation, so the pre-created user can be used (instead of
+     * creating and initializing a new user from scratch).
+     */
+    // TODO(b/140750212): add unit test
+    @GuardedBy("mUsersLock")
+    private @Nullable UserData getPreCreatedUserLU(@UserInfoFlag int flags) {
+        if (DBG) {
+            Slog.d(LOG_TAG, "getPreCreatedUser(): initialFlags= " + UserInfo.flagsToString(flags));
+        }
+        flags |= UserInfo.FLAG_FULL;
+        if (UserInfo.isGuest(flags) && areGuestUsersEphemeral()) {
+            flags |= UserInfo.FLAG_EPHEMERAL;
+        }
+        if (DBG) {
+            Slog.d(LOG_TAG, "getPreCreatedUser(): targetFlags= " + UserInfo.flagsToString(flags));
+        }
+        final int userSize = mUsers.size();
+        for (int i = 0; i < userSize; i++) {
+            final UserData user = mUsers.valueAt(i);
+            if (DBG) Slog.d(LOG_TAG, i + ":" + user.info.toFullString());
+            if (user.info.preCreated
+                    && (user.info.flags & ~UserInfo.FLAG_INITIALIZED) == flags) {
+                if (!user.info.isInitialized()) {
+                    Slog.w(LOG_TAG, "found pre-created user for flags "
+                            + "" + UserInfo.flagsToString(flags)
+                            + ", but it's not initialized yet: " + user.info.toFullString());
+                    continue;
+                }
+                return user;
+            }
+        }
+        return null;
+    }
+
     @VisibleForTesting
     UserData putUserInfo(UserInfo userInfo) {
         final UserData userData = new UserData();
@@ -3728,7 +3885,7 @@
         try {
             switch(cmd) {
                 case "list":
-                    return runList(pw);
+                    return runList(pw, shell);
                 default:
                     return shell.handleDefaultCommands(cmd);
             }
@@ -3738,17 +3895,58 @@
         return -1;
     }
 
-    private int runList(PrintWriter pw) throws RemoteException {
+    private int runList(PrintWriter pw, Shell shell) throws RemoteException {
+        boolean all = false;
+        boolean verbose = false;
+        String opt;
+        while ((opt = shell.getNextOption()) != null) {
+            switch (opt) {
+                case "-v":
+                    verbose = true;
+                    break;
+                case "--all":
+                    all = true;
+                    break;
+                default:
+                    pw.println("Invalid option: " + opt);
+                    return -1;
+            }
+        }
         final IActivityManager am = ActivityManager.getService();
-        final List<UserInfo> users = getUsers(false);
+        final List<UserInfo> users = getUsers(/* excludePartial= */ !all,
+                /* excludingDying=*/ false, /* excludePreCreated= */ !all);
         if (users == null) {
             pw.println("Error: couldn't get users");
             return 1;
         } else {
-            pw.println("Users:");
-            for (int i = 0; i < users.size(); i++) {
-                String running = am.isUserRunning(users.get(i).id, 0) ? " running" : "";
-                pw.println("\t" + users.get(i).toString() + running);
+            final int size = users.size();
+            int currentUser = UserHandle.USER_NULL;
+            if (verbose) {
+                pw.printf("%d users:\n\n", size);
+                currentUser = am.getCurrentUser().id;
+            } else {
+                // NOTE: the standard "list users" command is used by integration tests and
+                // hence should not be changed. If you need to add more info, use the
+                // verbose option.
+                pw.println("Users:");
+            }
+            for (int i = 0; i < size; i++) {
+                final UserInfo user = users.get(i);
+                final boolean running = am.isUserRunning(user.id, 0);
+                final boolean current = user.id == currentUser;
+                if (verbose) {
+                    pw.printf("%d: id=%d, name=%s, flags=%s%s%s%s%s\n", i, user.id, user.name,
+                            UserInfo.flagsToString(user.flags),
+                            running ? " (running)" : "",
+                            user.partial ? " (partial)" : "",
+                            user.preCreated ? " (pre-created)" : "",
+                            current ? " (current)" : "");
+                } else {
+                    // NOTE: the standard "list users" command is used by integration tests and
+                    // hence should not be changed. If you need to add more info, use the
+                    // verbose option.
+                    pw.printf("\t%s%s\n", user, running ? " running" : "");
+                }
             }
             return 0;
         }
@@ -3785,6 +3983,9 @@
                     if (userInfo.partial) {
                         pw.print(" <partial>");
                     }
+                    if (userInfo.preCreated) {
+                        pw.print(" <pre-created>");
+                    }
                     pw.println();
                     pw.print("    Flags: "); pw.print(userInfo.flags); pw.print(" (");
                     pw.print(UserInfo.flagsToString(userInfo.flags)); pw.println(")");
@@ -3867,10 +4068,10 @@
 
         // Dump some capabilities
         pw.println();
-        pw.println("  Max users: " + UserManager.getMaxSupportedUsers());
+        pw.print("  Max users: " + UserManager.getMaxSupportedUsers());
+        pw.println(" (limit reached: " + isUserLimitReached() + ")");
         pw.println("  Supports switchable users: " + UserManager.supportsMultipleUsers());
-        pw.println("  All guests ephemeral: " + Resources.getSystem().getBoolean(
-                com.android.internal.R.bool.config_guestUserEphemeral));
+        pw.println("  All guests ephemeral: " + areGuestUsersEphemeral());
         pw.println("  Is split-system user: " + UserManager.isSplitSystemUser());
         pw.println("  Is headless-system mode: " + UserManager.isHeadlessSystemUserMode());
         pw.println("  User version: " + mUserVersion);
@@ -3979,6 +4180,13 @@
         }
 
         @Override
+        public boolean isDeviceManaged() {
+            synchronized (mUsersLock) {
+                return mIsDeviceManaged;
+            }
+        }
+
+        @Override
         public void setUserManaged(@UserIdInt int userId, boolean isManaged) {
             synchronized (mUsersLock) {
                 mIsUserManaged.put(userId, isManaged);
@@ -3986,6 +4194,13 @@
         }
 
         @Override
+        public boolean isUserManaged(@UserIdInt int userId) {
+            synchronized (mUsersLock) {
+                return mIsUserManaged.get(userId);
+            }
+        }
+
+        @Override
         public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) {
             long ident = Binder.clearCallingIdentity();
             try {
@@ -4062,7 +4277,7 @@
         public UserInfo createUserEvenWhenDisallowed(String name, int flags,
                 String[] disallowedPackages) {
             UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL,
-                    disallowedPackages);
+                    /* preCreated= */ false, disallowedPackages);
             // Keep this in sync with UserManager.createUser
             if (user != null && !user.isAdmin() && !user.isDemo()) {
                 setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
@@ -4205,6 +4420,7 @@
             return restrictions != null && restrictions.getBoolean(restrictionKey);
         }
 
+        @Override
         public @Nullable UserInfo getUserInfo(@UserIdInt int userId) {
             UserData userData;
             synchronized (mUsersLock) {
@@ -4255,7 +4471,7 @@
             pw.println("  help");
             pw.println("    Print this help text.");
             pw.println("");
-            pw.println("  list");
+            pw.println("  list [-v] [-all]");
             pw.println("    Prints all users on the system.");
         }
     }
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 b831374..4213168 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -793,68 +793,62 @@
 
         final CheckPermissionDelegate checkPermissionDelegate;
         synchronized (mLock) {
+            if (mCheckPermissionDelegate == null)  {
+                return checkPermissionImpl(permName, pkgName, userId);
+            }
             checkPermissionDelegate = mCheckPermissionDelegate;
         }
-        if (checkPermissionDelegate == null)  {
-            return checkPermissionImpl(permName, pkgName, userId);
-        }
         return checkPermissionDelegate.checkPermission(permName, pkgName, userId,
-                this::checkPermissionImpl);
+                PermissionManagerService.this::checkPermissionImpl);
     }
 
-    private int checkPermissionImpl(@NonNull String permissionName, @NonNull String packageName,
-            @UserIdInt int userId) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(packageName);
+    private int checkPermissionImpl(String permName, String pkgName, int userId) {
+        final PackageParser.Package pkg = mPackageManagerInt.getPackage(pkgName);
         if (pkg == null) {
             return PackageManager.PERMISSION_DENIED;
         }
-        return checkPermissionInternal(pkg, true, permissionName, true, userId)
-                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
+        return checkPermissionInternal(pkg, true, permName, userId);
     }
 
-    private boolean checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
-            @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps,
-            @UserIdInt int userId) {
+    private int checkPermissionInternal(@NonNull Package pkg, boolean isPackageExplicit,
+            @NonNull String permissionName, @UserIdInt int userId) {
         final int callingUid = getCallingUid();
         if (isPackageExplicit || pkg.mSharedUserId == null) {
             if (mPackageManagerInt.filterAppAccess(pkg, callingUid, userId)) {
-                return false;
+                return PackageManager.PERMISSION_DENIED;
             }
         } else {
             if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
-                return false;
+                return PackageManager.PERMISSION_DENIED;
             }
         }
 
         final int uid = UserHandle.getUid(userId, pkg.applicationInfo.uid);
         final PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps == null) {
-            return false;
+            return PackageManager.PERMISSION_DENIED;
         }
         final PermissionsState permissionsState = ps.getPermissionsState();
 
-        if (checkSinglePermissionInternal(uid, permissionsState, permissionName,
-                useRequestedPermissionsForLegacyApps)) {
-            return true;
+        if (checkSinglePermissionInternal(uid, permissionsState, permissionName)) {
+            return PackageManager.PERMISSION_GRANTED;
         }
 
         final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
-        if (fullerPermissionName != null && checkSinglePermissionInternal(uid, permissionsState,
-                fullerPermissionName, useRequestedPermissionsForLegacyApps)) {
-            return true;
+        if (fullerPermissionName != null
+                && checkSinglePermissionInternal(uid, permissionsState, fullerPermissionName)) {
+            return PackageManager.PERMISSION_GRANTED;
         }
 
-        return false;
+        return PackageManager.PERMISSION_DENIED;
     }
 
     private boolean checkSinglePermissionInternal(int uid,
-            @NonNull PermissionsState permissionsState, @NonNull String permissionName,
-            boolean useRequestedPermissionsForLegacyApps) {
+            @NonNull PermissionsState permissionsState, @NonNull String permissionName) {
         boolean hasPermission = permissionsState.hasPermission(permissionName,
                 UserHandle.getUserId(uid));
 
-        if (!hasPermission && useRequestedPermissionsForLegacyApps
-                && mSettings.isPermissionRuntime(permissionName)) {
+        if (!hasPermission && mSettings.isPermissionRuntime(permissionName)) {
             final String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid);
             final int packageNamesSize = packageNames != null ? packageNames.length : 0;
             for (int i = 0; i < packageNamesSize; i++) {
@@ -897,13 +891,12 @@
             checkPermissionDelegate = mCheckPermissionDelegate;
         }
         return checkPermissionDelegate.checkUidPermission(permName, uid,
-                this::checkUidPermissionImpl);
+                PermissionManagerService.this::checkUidPermissionImpl);
     }
 
-    private int checkUidPermissionImpl(@NonNull String permissionName, int uid) {
+    private int checkUidPermissionImpl(String permName, int uid) {
         final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
-        return checkUidPermissionInternal(uid, pkg, permissionName, true)
-                ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED;
+        return checkUidPermissionInternal(pkg, uid, permName);
     }
 
     /**
@@ -913,25 +906,24 @@
      *
      * @see SystemConfig#getSystemPermissions()
      */
-    private boolean checkUidPermissionInternal(int uid, @Nullable Package pkg,
-            @NonNull String permissionName, boolean useRequestedPermissionsForLegacyApps) {
+    private int checkUidPermissionInternal(@Nullable Package pkg, int uid,
+            @NonNull String permissionName) {
         if (pkg != null) {
             final int userId = UserHandle.getUserId(uid);
-            return checkPermissionInternal(pkg, false, permissionName,
-                    useRequestedPermissionsForLegacyApps, userId);
+            return checkPermissionInternal(pkg, false, permissionName, userId);
         }
 
         if (checkSingleUidPermissionInternal(uid, permissionName)) {
-            return true;
+            return PackageManager.PERMISSION_GRANTED;
         }
 
         final String fullerPermissionName = FULLER_PERMISSION_MAP.get(permissionName);
         if (fullerPermissionName != null
                 && checkSingleUidPermissionInternal(uid, fullerPermissionName)) {
-            return true;
+            return PackageManager.PERMISSION_GRANTED;
         }
 
-        return false;
+        return PackageManager.PERMISSION_DENIED;
     }
 
     private boolean checkSingleUidPermissionInternal(int uid, @NonNull String permissionName) {
@@ -941,17 +933,6 @@
         }
     }
 
-    private int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName) {
-        boolean granted = isUidPermissionGranted(uid, permissionName);
-        // TODO: Foreground permissions.
-        return granted ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
-    }
-
-    private boolean isUidPermissionGranted(int uid, @NonNull String permissionName) {
-        final PackageParser.Package pkg = mPackageManagerInt.getPackage(uid);
-        return checkUidPermissionInternal(uid, pkg, permissionName, false);
-    }
-
     @Override
     public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
         mContext.enforceCallingOrSelfPermission(
@@ -1295,7 +1276,7 @@
         }
 
         if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
-                pkg.applicationInfo, UserHandle.of(userId), permName).canBeGranted()) {
+                pkg.applicationInfo, UserHandle.of(userId), permName).mayGrantPermission()) {
             Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                     + packageName);
             return;
@@ -1577,7 +1558,6 @@
             }
         };
 
-        final AppOpsManager appOpsManager = mContext.getSystemService(AppOpsManager.class);
         for (int i = 0; i < permissionCount; i++) {
             final String permName = pkg.requestedPermissions.get(i);
             final BasePermission bp;
@@ -1643,16 +1623,9 @@
 
             // If this permission was granted by default, make sure it is.
             if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+                // PermissionPolicyService will handle the app op for runtime permissions later.
                 grantRuntimePermissionInternal(permName, packageName, false,
                         Process.SYSTEM_UID, userId, delayingPermCallback);
-                // Allow app op later as we are holding mPackages
-                // PermissionPolicyService will handle the app op for foreground/background
-                // permissions.
-                String appOp = AppOpsManager.permissionToOp(permName);
-                if (appOp != null) {
-                    mHandler.post(() -> appOpsManager.setUidMode(appOp, uid,
-                            AppOpsManager.MODE_ALLOWED));
-                }
             // If permission review is enabled the permissions for a legacy apps
             // are represented as constantly granted runtime ones, so don't revoke.
             } else if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
@@ -1697,10 +1670,11 @@
         if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
             return null;
         }
+        DefaultBrowserProvider provider;
         synchronized (mLock) {
-            return mDefaultBrowserProvider == null
-                    ? null : mDefaultBrowserProvider.getDefaultBrowser(userId);
+            provider = mDefaultBrowserProvider;
         }
+        return provider != null ? provider.getDefaultBrowser(userId) : null;
     }
 
     @Override
@@ -1716,23 +1690,27 @@
 
     private boolean setDefaultBrowserInternal(String packageName, boolean async,
             boolean doGrant, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            return false;
+        }
+        DefaultBrowserProvider provider;
         synchronized (mLock) {
-            if (userId == UserHandle.USER_ALL) {
+            provider = mDefaultBrowserProvider;
+        }
+        if (provider == null) {
+            return false;
+        }
+        if (async) {
+            provider.setDefaultBrowserAsync(packageName, userId);
+        } else {
+            if (!provider.setDefaultBrowser(packageName, userId)) {
                 return false;
             }
-            if (mDefaultBrowserProvider == null) {
-                return false;
-            }
-            if (async) {
-                mDefaultBrowserProvider.setDefaultBrowserAsync(packageName, userId);
-            } else {
-                if (!mDefaultBrowserProvider.setDefaultBrowser(packageName, userId)) {
-                    return false;
-                }
-            }
-            if (doGrant && packageName != null) {
-                mDefaultPermissionGrantPolicy
-                        .grantDefaultPermissionsToDefaultBrowser(packageName, userId);
+        }
+        if (doGrant && packageName != null) {
+            synchronized (mLock) {
+                mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+                        userId);
             }
         }
         return true;
@@ -3407,6 +3385,9 @@
         final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 
+        final int compatFlags = PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED
+                | PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
+
         final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
                 >= Build.VERSION_CODES.M;
 
@@ -3430,12 +3411,11 @@
                                 callingUid, userId, callback);
                     }
                 } else {
-                    // In permission review mode we clear the review flag when we
-                    // are asked to install the app with all permissions granted.
-                    if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
-                        updatePermissionFlagsInternal(permission, pkg.packageName,
-                                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid,
-                                userId, false, callback);
+                    // In permission review mode we clear the review flag and the revoked compat
+                    // flag when we are asked to install the app with all permissions granted.
+                    if ((flags & compatFlags) != 0) {
+                        updatePermissionFlagsInternal(permission, pkg.packageName, compatFlags,
+                                0, callingUid, userId, false, callback);
                     }
                 }
             }
@@ -4334,15 +4314,17 @@
 
         @Override
         public void setDefaultHome(String packageName, int userId, Consumer<Boolean> callback) {
-            synchronized (mLock) {
-                if (userId == UserHandle.USER_ALL) {
-                    return;
-                }
-                if (mDefaultHomeProvider == null) {
-                    return;
-                }
-                mDefaultHomeProvider.setDefaultHomeAsync(packageName, userId, callback);
+            if (userId == UserHandle.USER_ALL) {
+                return;
             }
+            DefaultHomeProvider provider;
+            synchronized (mLock) {
+                provider = mDefaultHomeProvider;
+            }
+            if (provider == null) {
+                return;
+            }
+            provider.setDefaultHomeAsync(packageName, userId, callback);
         }
 
         @Override
@@ -4403,26 +4385,29 @@
 
         @Override
         public String getDefaultBrowser(int userId) {
+            DefaultBrowserProvider provider;
             synchronized (mLock) {
-                return mDefaultBrowserProvider == null
-                        ? null : mDefaultBrowserProvider.getDefaultBrowser(userId);
+                provider = mDefaultBrowserProvider;
             }
+            return provider != null ? provider.getDefaultBrowser(userId) : null;
         }
 
         @Override
         public String getDefaultDialer(int userId) {
+            DefaultDialerProvider provider;
             synchronized (mLock) {
-                return mDefaultDialerProvider == null
-                        ? null : mDefaultDialerProvider.getDefaultDialer(userId);
+                provider = mDefaultDialerProvider;
             }
+            return provider != null ? provider.getDefaultDialer(userId) : null;
         }
 
         @Override
         public String getDefaultHome(int userId) {
+            DefaultHomeProvider provider;
             synchronized (mLock) {
-                return mDefaultHomeProvider == null
-                        ? null : mDefaultHomeProvider.getDefaultHome(userId);
+                provider = mDefaultHomeProvider;
             }
+            return provider != null ? provider.getDefaultHome(userId) : null;
         }
 
         @Override
@@ -4465,12 +4450,6 @@
                         StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
             }
         }
-
-        @Override
-        public int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName) {
-            return PermissionManagerService.this.computeRuntimePermissionAppOpMode(uid,
-                    permissionName);
-        }
     }
 
     private static final class OnPermissionChangeListeners extends Handler {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 8f22f92..04ec5ba 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -445,13 +445,4 @@
 
     /** Called when a new user has been created. */
     public abstract void onNewUserCreated(@UserIdInt int userId);
-
-    /**
-     * Compute an app op mode based on its runtime permission state.
-     *
-     * @param uid the uid for the app op
-     * @param permissionName the permission name for the app op
-     * @return the computed mode
-     */
-    public abstract int computeRuntimePermissionAppOpMode(int uid, @NonNull String permissionName);
 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 1bf319d..77c16e3 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -17,13 +17,12 @@
 package com.android.server.policy;
 
 import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.MODE_ERRORED;
 import static android.app.AppOpsManager.MODE_FOREGROUND;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
 import android.annotation.NonNull;
@@ -157,13 +156,12 @@
                     appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
                 } else if (perm.isSoftRestricted()) {
                     appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
-
                     SoftRestrictedPermissionPolicy policy =
                             SoftRestrictedPermissionPolicy.forPermission(null, null, null,
                                     perm.name);
-                    if (policy.resolveAppOp() != OP_NONE) {
-                        appOpsService.startWatchingMode(policy.resolveAppOp(), null,
-                                appOpsListener);
+                    int extraAppOp = policy.getExtraAppOpCode();
+                    if (extraAppOp != OP_NONE) {
+                        appOpsService.startWatchingMode(extraAppOp, null, appOpsListener);
                     }
                 }
             }
@@ -395,24 +393,6 @@
         private final @NonNull SparseIntArray mAllUids = new SparseIntArray();
 
         /**
-         * All ops that need to be set to default
-         *
-         * Currently, only used by the restricted permissions logic.
-         *
-         * @see #syncPackages
-         */
-        private final @NonNull ArrayList<OpToChange> mOpsToDefault = new ArrayList<>();
-
-        /**
-         * All ops that need to be flipped to allow if default.
-         *
-         * Currently, only used by the restricted permissions logic.
-         *
-         * @see #syncPackages
-         */
-        private final @NonNull ArrayList<OpToChange> mOpsToAllowIfDefault = new ArrayList<>();
-
-        /**
          * All ops that need to be flipped to allow.
          *
          * @see #syncPackages
@@ -420,15 +400,6 @@
         private final @NonNull ArrayList<OpToChange> mOpsToAllow = new ArrayList<>();
 
         /**
-         * All ops that need to be flipped to ignore if default.
-         *
-         * Currently, only used by the restricted permissions logic.
-         *
-         * @see #syncPackages
-         */
-        private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfDefault = new ArrayList<>();
-
-        /**
          * All ops that need to be flipped to ignore.
          *
          * @see #syncPackages
@@ -436,6 +407,15 @@
         private final @NonNull ArrayList<OpToChange> mOpsToIgnore = new ArrayList<>();
 
         /**
+         * All ops that need to be flipped to ignore if not allowed.
+         *
+         * Currently, only used by soft restricted permissions logic.
+         *
+         * @see #syncPackages
+         */
+        private final @NonNull ArrayList<OpToChange> mOpsToIgnoreIfNotAllowed = new ArrayList<>();
+
+        /**
          * All ops that need to be flipped to foreground.
          *
          * Currently, only used by the foreground/background permissions logic.
@@ -444,16 +424,6 @@
          */
         private final @NonNull ArrayList<OpToChange> mOpsToForeground = new ArrayList<>();
 
-        /**
-         * All ops that need to be flipped to foreground if allow.
-         *
-         * Currently, only used by the foreground/background permissions logic.
-         *
-         * @see #syncPackages
-         */
-        private final @NonNull ArrayList<OpToChange> mOpsToForegroundIfAllow =
-                new ArrayList<>();
-
         PermissionToOpSynchroniser(@NonNull Context context) {
             mContext = context;
             mPackageManager = context.getPackageManager();
@@ -463,7 +433,7 @@
         /**
          * Set app ops that were added in {@link #addPackage}.
          *
-         * <p>This processes ops previously added by {@link #addOpIfRestricted}
+         * <p>This processes ops previously added by {@link #addAppOps(PackageInfo, String)}
          */
         private void syncPackages() {
             // Remember which ops were already set. This makes sure that we always set the most
@@ -479,32 +449,6 @@
                 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
 
-            final int allowIfDefaultCount = mOpsToAllowIfDefault.size();
-            for (int i = 0; i < allowIfDefaultCount; i++) {
-                final OpToChange op = mOpsToAllowIfDefault.get(i);
-                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
-                    continue;
-                }
-
-                boolean wasSet = setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
-                if (wasSet) {
-                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
-                }
-            }
-
-            final int foregroundIfAllowedCount = mOpsToForegroundIfAllow.size();
-            for (int i = 0; i < foregroundIfAllowedCount; i++) {
-                final OpToChange op = mOpsToForegroundIfAllow.get(i);
-                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
-                    continue;
-                }
-
-                boolean wasSet = setUidModeForegroundIfAllow(op.code, op.uid, op.packageName);
-                if (wasSet) {
-                    alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
-                }
-            }
-
             final int foregroundCount = mOpsToForeground.size();
             for (int i = 0; i < foregroundCount; i++) {
                 final OpToChange op = mOpsToForeground.get(i);
@@ -527,180 +471,154 @@
                 alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
             }
 
-            final int ignoreIfDefaultCount = mOpsToIgnoreIfDefault.size();
-            for (int i = 0; i < ignoreIfDefaultCount; i++) {
-                final OpToChange op = mOpsToIgnoreIfDefault.get(i);
+            final int ignoreIfNotAllowedCount = mOpsToIgnoreIfNotAllowed.size();
+            for (int i = 0; i < ignoreIfNotAllowedCount; i++) {
+                final OpToChange op = mOpsToIgnoreIfNotAllowed.get(i);
                 if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
                     continue;
                 }
 
-                boolean wasSet = setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName);
+                boolean wasSet = setUidModeIgnoredIfNotAllowed(op.code, op.uid, op.packageName);
                 if (wasSet) {
                     alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
                 }
             }
-
-            final int defaultCount = mOpsToDefault.size();
-            for (int i = 0; i < defaultCount; i++) {
-                final OpToChange op = mOpsToDefault.get(i);
-                if (alreadySetAppOps.indexOfKey(IntPair.of(op.uid, op.code)) >= 0) {
-                    continue;
-                }
-
-                setUidModeDefault(op.code, op.uid, op.packageName);
-                alreadySetAppOps.put(IntPair.of(op.uid, op.code), 1);
-            }
         }
 
         /**
-         * Add op that belong to a restricted permission for later processing in
-         * {@link #syncPackages()}.
-         *
-         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
-         *
-         * @param permissionInfo The permission that is currently looked at
-         * @param pkg The package looked at
+         * Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
          */
-        private void addOpIfRestricted(@NonNull PermissionInfo permissionInfo,
-                @NonNull PackageInfo pkg) {
-            final String permission = permissionInfo.name;
-            final int opCode = getSwitchOp(permission);
-            final int uid = pkg.applicationInfo.uid;
-
-            if (!permissionInfo.isRestricted()) {
+        private void addAppOps(@NonNull PackageInfo packageInfo, @NonNull String permissionName) {
+            PermissionInfo permissionInfo = getPermissionInfo(permissionName);
+            if (permissionInfo == null) {
                 return;
             }
-
-            final boolean applyRestriction =
-                    (mPackageManager.getPermissionFlags(permission, pkg.packageName,
-                    mContext.getUser()) & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-
-            if (permissionInfo.isHardRestricted()) {
-                if (opCode != OP_NONE) {
-                    if (applyRestriction) {
-                        mOpsToDefault.add(new OpToChange(uid, pkg.packageName, opCode));
-                    } else {
-                        mOpsToAllowIfDefault.add(new OpToChange(uid, pkg.packageName, opCode));
-                    }
-                }
-            } else if (permissionInfo.isSoftRestricted()) {
-                final SoftRestrictedPermissionPolicy policy =
-                        SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo,
-                                mContext.getUser(), permission);
-
-                if (opCode != OP_NONE) {
-                    if (policy.canBeGranted()) {
-                        mOpsToAllowIfDefault.add(new OpToChange(uid, pkg.packageName, opCode));
-                    } else {
-                        mOpsToDefault.add(new OpToChange(uid, pkg.packageName, opCode));
-                    }
-                }
-
-                final int op = policy.resolveAppOp();
-                if (op != OP_NONE) {
-                    switch (policy.getDesiredOpMode()) {
-                        case MODE_DEFAULT:
-                            mOpsToDefault.add(new OpToChange(uid, pkg.packageName, op));
-                            break;
-                        case MODE_ALLOWED:
-                            if (policy.shouldSetAppOpIfNotDefault()) {
-                                mOpsToAllow.add(new OpToChange(uid, pkg.packageName, op));
-                            } else {
-                                mOpsToAllowIfDefault.add(
-                                        new OpToChange(uid, pkg.packageName, op));
-                            }
-                            break;
-                        case MODE_FOREGROUND:
-                            Slog.wtf(LOG_TAG,
-                                    "Setting appop to foreground is not implemented");
-                            break;
-                        case MODE_IGNORED:
-                            if (policy.shouldSetAppOpIfNotDefault()) {
-                                mOpsToIgnore.add(new OpToChange(uid, pkg.packageName, op));
-                            } else {
-                                mOpsToIgnoreIfDefault.add(
-                                        new OpToChange(uid, pkg.packageName,
-                                                op));
-                            }
-                            break;
-                        case MODE_ERRORED:
-                            Slog.wtf(LOG_TAG, "Setting appop to errored is not implemented");
-                    }
-                }
-            }
+            addPermissionAppOp(packageInfo, permissionInfo);
+            addExtraAppOp(packageInfo, permissionInfo);
         }
 
-        private boolean isBgPermRestricted(@NonNull String pkg, @NonNull String perm, int uid) {
-            try {
-                final PermissionInfo bgPermInfo = mPackageManager.getPermissionInfo(perm, 0);
-
-                if (bgPermInfo.isSoftRestricted()) {
-                    Slog.wtf(LOG_TAG, "Support for soft restricted background permissions not "
-                            + "implemented");
-                }
-
-                return bgPermInfo.isHardRestricted() && (mPackageManager.getPermissionFlags(
-                                perm, pkg, UserHandle.getUserHandleForUid(uid))
-                                & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
-            } catch (NameNotFoundException e) {
-                Slog.w(LOG_TAG, "Cannot read permission state of " + perm, e);
-                return false;
-            }
-        }
-
-        /**
-         * Add op that belong to a foreground permission for later processing in
-         * {@link #syncPackages()}.
-         *
-         * <p>Note: Called with the package lock held. Do <u>not</u> call into app-op manager.
-         *
-         * @param permissionInfo The permission that is currently looked at
-         * @param pkg The package looked at
-         */
-        private void addOpIfFgPermissions(@NonNull PermissionInfo permissionInfo,
-                @NonNull PackageInfo pkg) {
-            final String bgPermissionName = permissionInfo.backgroundPermission;
-
-            if (bgPermissionName == null) {
+        private void addPermissionAppOp(@NonNull PackageInfo packageInfo,
+                @NonNull PermissionInfo permissionInfo) {
+            if (!permissionInfo.isRuntime()) {
                 return;
             }
 
-            final String permission = permissionInfo.name;
-            final int opCode = getSwitchOp(permission);
-            final String pkgName = pkg.packageName;
-            final int uid = pkg.applicationInfo.uid;
-
-            // App does not support runtime permissions. Hence the state is encoded in the app-op.
-            // To not override unrecoverable state don't change app-op unless bg perm is reviewed.
-            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) {
-                // If the review is required for this permission, the grant state does not
-                // really matter. To have a stable state, don't change the app-op if review is still
-                // pending.
-                int flags = mPackageManager.getPermissionFlags(bgPermissionName,
-                        pkg.packageName, UserHandle.getUserHandleForUid(uid));
-
-                if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0
-                        && isBgPermRestricted(pkgName, bgPermissionName, uid)) {
-                    mOpsToForegroundIfAllow.add(new OpToChange(uid, pkgName, opCode));
-                }
-
+            String permissionName = permissionInfo.name;
+            String packageName = packageInfo.packageName;
+            int permissionFlags = mPackageManager.getPermissionFlags(permissionName,
+                    packageName, mContext.getUser());
+            boolean isReviewRequired = (permissionFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;
+            if (isReviewRequired) {
                 return;
             }
 
-            if (mPackageManager.checkPermission(permission, pkgName)
-                    == PackageManager.PERMISSION_GRANTED) {
-                final boolean isBgHardRestricted = isBgPermRestricted(pkgName, bgPermissionName,
-                        uid);
-                final boolean isBgPermGranted = mPackageManager.checkPermission(bgPermissionName,
-                        pkgName) == PackageManager.PERMISSION_GRANTED;
+            // TODO: COARSE_LOCATION and FINE_LOCATION shares the same app op. We are solving this
+            //  with switch op but once we start syncing single permission this won't work.
+            int appOpCode = getSwitchOp(permissionName);
+            if (appOpCode == OP_NONE) {
+                // Note that background permissions don't have an associated app op.
+                return;
+            }
 
-                if (!isBgHardRestricted && isBgPermGranted) {
-                    mOpsToAllow.add(new OpToChange(uid, pkgName, opCode));
+            int appOpMode;
+            boolean shouldGrantAppOp = shouldGrantAppOp(packageInfo, permissionInfo);
+            if (shouldGrantAppOp) {
+                if (permissionInfo.backgroundPermission != null) {
+                    PermissionInfo backgroundPermissionInfo = getPermissionInfo(
+                            permissionInfo.backgroundPermission);
+                    boolean shouldGrantBackgroundAppOp = backgroundPermissionInfo != null
+                            && shouldGrantAppOp(packageInfo, backgroundPermissionInfo);
+                    appOpMode = shouldGrantBackgroundAppOp ? MODE_ALLOWED : MODE_FOREGROUND;
                 } else {
-                    mOpsToForeground.add(new OpToChange(uid, pkgName, opCode));
+                    appOpMode = MODE_ALLOWED;
                 }
             } else {
-                mOpsToIgnore.add(new OpToChange(uid, pkgName, opCode));
+                appOpMode = MODE_IGNORED;
+            }
+
+            int uid = packageInfo.applicationInfo.uid;
+            OpToChange opToChange = new OpToChange(uid, packageName, appOpCode);
+            switch (appOpMode) {
+                case MODE_ALLOWED:
+                    mOpsToAllow.add(opToChange);
+                    break;
+                case MODE_FOREGROUND:
+                    mOpsToForeground.add(opToChange);
+                    break;
+                case MODE_IGNORED:
+                    mOpsToIgnore.add(opToChange);
+                    break;
+            }
+        }
+
+        @Nullable
+        private PermissionInfo getPermissionInfo(@NonNull String permissionName) {
+            try {
+                return mPackageManager.getPermissionInfo(permissionName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                return null;
+            }
+        }
+
+        private boolean shouldGrantAppOp(@NonNull PackageInfo packageInfo,
+                @NonNull PermissionInfo permissionInfo) {
+            String permissionName = permissionInfo.name;
+            String packageName = packageInfo.packageName;
+            boolean isGranted = mPackageManager.checkPermission(permissionName, packageName)
+                    == PackageManager.PERMISSION_GRANTED;
+            if (!isGranted) {
+                return false;
+            }
+
+            int permissionFlags = mPackageManager.getPermissionFlags(permissionName, packageName,
+                    mContext.getUser());
+            boolean isRevokedCompat = (permissionFlags & FLAG_PERMISSION_REVOKED_COMPAT)
+                    == FLAG_PERMISSION_REVOKED_COMPAT;
+            if (isRevokedCompat) {
+                return false;
+            }
+
+            if (permissionInfo.isHardRestricted()) {
+                boolean shouldApplyRestriction =
+                        (permissionFlags & FLAG_PERMISSION_APPLY_RESTRICTION)
+                                == FLAG_PERMISSION_APPLY_RESTRICTION;
+                return !shouldApplyRestriction;
+            } else if (permissionInfo.isSoftRestricted()) {
+                SoftRestrictedPermissionPolicy policy =
+                        SoftRestrictedPermissionPolicy.forPermission(mContext,
+                                packageInfo.applicationInfo, mContext.getUser(), permissionName);
+                return policy.mayGrantPermission();
+            } else {
+                return true;
+            }
+        }
+
+        private void addExtraAppOp(@NonNull PackageInfo packageInfo,
+                @NonNull PermissionInfo permissionInfo) {
+            if (!permissionInfo.isSoftRestricted()) {
+                return;
+            }
+
+            String permissionName = permissionInfo.name;
+            SoftRestrictedPermissionPolicy policy =
+                    SoftRestrictedPermissionPolicy.forPermission(mContext,
+                            packageInfo.applicationInfo, mContext.getUser(), permissionName);
+            int extraOpCode = policy.getExtraAppOpCode();
+            if (extraOpCode == OP_NONE) {
+                return;
+            }
+
+            int uid = packageInfo.applicationInfo.uid;
+            String packageName = packageInfo.packageName;
+            OpToChange extraOpToChange = new OpToChange(uid, packageName, extraOpCode);
+            if (policy.mayAllowExtraAppOp()) {
+                mOpsToAllow.add(extraOpToChange);
+            } else {
+                if (policy.mayDenyExtraAppOpIfGranted()) {
+                    mOpsToIgnore.add(extraOpToChange);
+                } else {
+                    mOpsToIgnoreIfNotAllowed.add(extraOpToChange);
+                }
             }
         }
 
@@ -726,77 +644,44 @@
             }
 
             for (String permission : pkg.requestedPermissions) {
-                final int opCode = getSwitchOp(permission);
-                if (opCode == OP_NONE) {
-                    continue;
-                }
-
-                final PermissionInfo permissionInfo;
-                try {
-                    permissionInfo = mPackageManager.getPermissionInfo(permission, 0);
-                } catch (PackageManager.NameNotFoundException e) {
-                    continue;
-                }
-
-                addOpIfRestricted(permissionInfo, pkg);
-                addOpIfFgPermissions(permissionInfo, pkg);
+                addAppOps(pkg, permission);
             }
         }
 
-        private boolean setUidModeAllowedIfDefault(int opCode, int uid,
-                @NonNull String packageName) {
-            return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_ALLOWED, packageName);
-        }
-
         private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
             setUidMode(opCode, uid, MODE_ALLOWED, packageName);
         }
 
-        private boolean setUidModeForegroundIfAllow(int opCode, int uid,
-                @NonNull String packageName) {
-            return setUidModeIfMode(opCode, uid, MODE_ALLOWED, MODE_FOREGROUND, packageName);
-        }
-
         private void setUidModeForeground(int opCode, int uid, @NonNull String packageName) {
             setUidMode(opCode, uid, MODE_FOREGROUND, packageName);
         }
 
-        private boolean setUidModeIgnoredIfDefault(int opCode, int uid,
-                @NonNull String packageName) {
-            return setUidModeIfMode(opCode, uid, MODE_DEFAULT, MODE_IGNORED, packageName);
-        }
-
         private void setUidModeIgnored(int opCode, int uid, @NonNull String packageName) {
             setUidMode(opCode, uid, MODE_IGNORED, packageName);
         }
 
+        private boolean setUidModeIgnoredIfNotAllowed(int opCode, int uid,
+                @NonNull String packageName) {
+            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
+                    opCode), uid, packageName);
+            if (currentMode != MODE_ALLOWED) {
+                if (currentMode != MODE_IGNORED) {
+                    mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
+                }
+                return true;
+            }
+            return false;
+        }
+
         private void setUidMode(int opCode, int uid, int mode,
                 @NonNull String packageName) {
             final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                     .opToPublicName(opCode), uid, packageName);
-
             if (currentMode != mode) {
                 mAppOpsManager.setUidMode(opCode, uid, mode);
             }
         }
 
-        private boolean setUidModeIfMode(int opCode, int uid, int requiredModeBefore, int newMode,
-                @NonNull String packageName) {
-            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
-                    .opToPublicName(opCode), uid, packageName);
-
-            if (currentMode == requiredModeBefore) {
-                mAppOpsManager.setUidMode(opCode, uid, newMode);
-                return true;
-            }
-
-            return false;
-        }
-
-        private void setUidModeDefault(int opCode, int uid, String packageName) {
-            setUidMode(opCode, uid, MODE_DEFAULT, packageName);
-        }
-
         private class OpToChange {
             final int uid;
             final @NonNull String packageName;
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index c1a6dbd..b0f22e4 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -18,9 +18,6 @@
 
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
@@ -55,22 +52,7 @@
     private static final SoftRestrictedPermissionPolicy DUMMY_POLICY =
             new SoftRestrictedPermissionPolicy() {
                 @Override
-                public int resolveAppOp() {
-                    return OP_NONE;
-                }
-
-                @Override
-                public int getDesiredOpMode() {
-                    return MODE_DEFAULT;
-                }
-
-                @Override
-                public boolean shouldSetAppOpIfNotDefault() {
-                    return false;
-                }
-
-                @Override
-                public boolean canBeGranted() {
+                public boolean mayGrantPermission() {
                     return true;
                 }
             };
@@ -114,10 +96,8 @@
      * Get the policy for a soft restricted permission.
      *
      * @param context A context to use
-     * @param appInfo The application the permission belongs to. Can be {@code null}, but then
-     *                only {@link #resolveAppOp} will work.
-     * @param user The user the app belongs to. Can be {@code null}, but then only
-     *             {@link #resolveAppOp} will work.
+     * @param appInfo The application the permission belongs to.
+     * @param user The user the app belongs to.
      * @param permission The name of the permission
      *
      * @return The policy for this permission
@@ -130,82 +110,46 @@
             // where the restricted state allows the permission but only for accessing the medial
             // collections.
             case READ_EXTERNAL_STORAGE: {
-                final int flags;
-                final boolean applyRestriction;
                 final boolean isWhiteListed;
-                final boolean hasRequestedLegacyExternalStorage;
+                boolean shouldApplyRestriction;
                 final int targetSDK;
+                final boolean hasRequestedLegacyExternalStorage;
 
                 if (appInfo != null) {
                     PackageManager pm = context.getPackageManager();
-                    flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
-                    applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
+                    int flags = pm.getPermissionFlags(permission, appInfo.packageName, user);
                     isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
+                    shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
                     targetSDK = getMinimumTargetSDK(context, appInfo, user);
-
-                    boolean hasAnyRequestedLegacyExternalStorage =
-                            appInfo.hasRequestedLegacyExternalStorage();
-
-                    // hasRequestedLegacyExternalStorage is per package. To make sure two apps in
-                    // the same shared UID do not fight over what to set, always compute the
-                    // combined hasRequestedLegacyExternalStorage
-                    String[] uidPkgs = pm.getPackagesForUid(appInfo.uid);
-                    if (uidPkgs != null) {
-                        for (String uidPkg : uidPkgs) {
-                            if (!uidPkg.equals(appInfo.packageName)) {
-                                ApplicationInfo uidPkgInfo;
-                                try {
-                                    uidPkgInfo = pm.getApplicationInfoAsUser(uidPkg, 0, user);
-                                } catch (PackageManager.NameNotFoundException e) {
-                                    continue;
-                                }
-
-                                hasAnyRequestedLegacyExternalStorage |=
-                                        uidPkgInfo.hasRequestedLegacyExternalStorage();
-                            }
-                        }
-                    }
-
-                    hasRequestedLegacyExternalStorage = hasAnyRequestedLegacyExternalStorage;
+                    hasRequestedLegacyExternalStorage = hasUidRequestedLegacyExternalStorage(
+                            appInfo.uid, context);
                 } else {
-                    flags = 0;
-                    applyRestriction = false;
                     isWhiteListed = false;
-                    hasRequestedLegacyExternalStorage = false;
+                    shouldApplyRestriction = false;
                     targetSDK = 0;
+                    hasRequestedLegacyExternalStorage = false;
                 }
 
+                // We have a check in PermissionPolicyService.PermissionToOpSynchroniser.setUidMode
+                // to prevent apps losing files in legacy storage, because we are holding the
+                // package manager lock here. If we ever remove this policy that check should be
+                // removed as well.
                 return new SoftRestrictedPermissionPolicy() {
                     @Override
-                    public int resolveAppOp() {
+                    public boolean mayGrantPermission() {
+                        return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
+                    }
+                    @Override
+                    public int getExtraAppOpCode() {
                         return OP_LEGACY_STORAGE;
                     }
-
                     @Override
-                    public int getDesiredOpMode() {
-                        if (applyRestriction) {
-                            return MODE_DEFAULT;
-                        } else if (hasRequestedLegacyExternalStorage) {
-                            return MODE_ALLOWED;
-                        } else {
-                            return MODE_IGNORED;
-                        }
+                    public boolean mayAllowExtraAppOp() {
+                        return !shouldApplyRestriction && hasRequestedLegacyExternalStorage;
                     }
-
                     @Override
-                    public boolean shouldSetAppOpIfNotDefault() {
-                        // Do not switch from allowed -> ignored as this would mean to retroactively
-                        // turn on isolated storage. This will make the app loose all its files.
-                        return getDesiredOpMode() != MODE_IGNORED;
-                    }
-
-                    @Override
-                    public boolean canBeGranted() {
-                        if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) {
-                            return true;
-                        } else {
-                            return false;
-                        }
+                    public boolean mayDenyExtraAppOpIfGranted() {
+                        return shouldApplyRestriction;
                     }
                 };
             }
@@ -225,22 +169,7 @@
 
                 return new SoftRestrictedPermissionPolicy() {
                     @Override
-                    public int resolveAppOp() {
-                        return OP_NONE;
-                    }
-
-                    @Override
-                    public int getDesiredOpMode() {
-                        return MODE_DEFAULT;
-                    }
-
-                    @Override
-                    public boolean shouldSetAppOpIfNotDefault() {
-                        return false;
-                    }
-
-                    @Override
-                    public boolean canBeGranted() {
+                    public boolean mayGrantPermission() {
                         return isWhiteListed || targetSDK >= Build.VERSION_CODES.Q;
                     }
                 };
@@ -250,25 +179,51 @@
         }
     }
 
-    /**
-     * @return An app op to be changed based on the state of the permission or
-     * {@link AppOpsManager#OP_NONE} if not app-op should be set.
-     */
-    public abstract int resolveAppOp();
-
-    /**
-     * @return The mode the {@link #resolveAppOp() app op} should be in.
-     */
-    public abstract @AppOpsManager.Mode int getDesiredOpMode();
-
-    /**
-     * @return If the {@link #resolveAppOp() app op} should be set even if the app-op is currently
-     * not {@link AppOpsManager#MODE_DEFAULT}.
-     */
-    public abstract boolean shouldSetAppOpIfNotDefault();
+    private static boolean hasUidRequestedLegacyExternalStorage(int uid, @NonNull Context context) {
+        PackageManager packageManager = context.getPackageManager();
+        String[] packageNames = packageManager.getPackagesForUid(uid);
+        if (packageNames == null) {
+            return false;
+        }
+        UserHandle user = UserHandle.getUserHandleForUid(uid);
+        for (String packageName : packageNames) {
+            ApplicationInfo applicationInfo;
+            try {
+                applicationInfo = packageManager.getApplicationInfoAsUser(packageName, 0, user);
+            } catch (PackageManager.NameNotFoundException e) {
+                continue;
+            }
+            if (applicationInfo.hasRequestedLegacyExternalStorage()) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     /**
      * @return If the permission can be granted
      */
-    public abstract boolean canBeGranted();
+    public abstract boolean mayGrantPermission();
+
+    /**
+     * @return An app op to be changed based on the state of the permission or
+     * {@link AppOpsManager#OP_NONE} if not app-op should be set.
+     */
+    public int getExtraAppOpCode() {
+        return OP_NONE;
+    }
+
+    /**
+     * @return Whether the {@link #getExtraAppOpCode() app op} may be granted.
+     */
+    public boolean mayAllowExtraAppOp() {
+        return false;
+    }
+
+    /**
+     * @return Whether the {@link #getExtraAppOpCode() app op} may be denied if was granted.
+     */
+    public boolean mayDenyExtraAppOpIfGranted() {
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 712012d..017c684 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -21,6 +21,7 @@
 import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
@@ -34,9 +35,9 @@
 import com.android.server.LocalServices;
 import com.android.server.role.RoleManagerService;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Logic to retrieve the various legacy(pre-Q) equivalents of role holders.
@@ -125,9 +126,21 @@
             }
             case RoleManager.ROLE_HOME: {
                 PackageManager packageManager = mContext.getPackageManager();
-                List<ResolveInfo> resolveInfos = new ArrayList<>();
-                ComponentName componentName = packageManager.getHomeActivities(resolveInfos);
-                String packageName = componentName != null ? componentName.getPackageName() : null;
+                String packageName;
+                if (packageManager.isDeviceUpgrading()) {
+                    ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(
+                            new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
+                            PackageManager.MATCH_DEFAULT_ONLY
+                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+                    packageName = resolveInfo != null && resolveInfo.activityInfo != null
+                            ? resolveInfo.activityInfo.packageName : null;
+                    if (packageName != null && isSettingsApplication(packageName, userId)) {
+                        packageName = null;
+                    }
+                } else {
+                    packageName = null;
+                }
                 return CollectionUtils.singletonOrEmpty(packageName);
             }
             case RoleManager.ROLE_EMERGENCY: {
@@ -142,4 +155,16 @@
             }
         }
     }
+
+    private boolean isSettingsApplication(@NonNull String packageName, @UserIdInt int userId) {
+        PackageManager packageManager = mContext.getPackageManager();
+        ResolveInfo resolveInfo = packageManager.resolveActivityAsUser(new Intent(
+                Settings.ACTION_SETTINGS), PackageManager.MATCH_DEFAULT_ONLY
+                | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
+        if (resolveInfo == null || resolveInfo.activityInfo == null) {
+            return false;
+        }
+        return Objects.equals(packageName, resolveInfo.activityInfo.packageName);
+    }
 }
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index bf8c042..282fed8 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -269,6 +269,7 @@
         maybeMigrateRole(RoleManager.ROLE_DIALER, userId);
         maybeMigrateRole(RoleManager.ROLE_SMS, userId);
         maybeMigrateRole(RoleManager.ROLE_EMERGENCY, userId);
+        maybeMigrateRole(RoleManager.ROLE_HOME, userId);
 
         // Some package state has changed, so grant default roles again.
         Slog.i(LOG_TAG, "Granting default roles...");
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 3f9cc83b..1123f70 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -51,7 +51,7 @@
      * {@code userIds}. Updates said {@code packageRollbackInfo} with the inodes of the CE user data
      * snapshot folders.
      */
-    @GuardedBy("rollback.getLock")
+    @GuardedBy("rollback.mLock")
     // TODO(b/136241838): Move into Rollback and synchronize there.
     public void snapshotAppData(
             int snapshotId, PackageRollbackInfo packageRollbackInfo, int[] userIds) {
@@ -78,7 +78,6 @@
                         + packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
             }
         }
-        packageRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
     }
 
     /**
@@ -89,7 +88,7 @@
      *         to {@code packageRollbackInfo} are restricted to the removal or addition of {@code
      *         userId} to the list of pending backups or restores.
      */
-    @GuardedBy("rollback.getLock")
+    @GuardedBy("rollback.mLock")
     // TODO(b/136241838): Move into Rollback and synchronize there.
     public boolean restoreAppData(int rollbackId, PackageRollbackInfo packageRollbackInfo,
             int userId, int appId, String seInfo) {
@@ -134,7 +133,7 @@
      * Deletes an app data snapshot with a given {@code rollbackId} for a specified package
      * {@code packageName} for a given {@code user}.
      */
-    @GuardedBy("rollback.getLock")
+    @GuardedBy("rollback.mLock")
     // TODO(b/136241838): Move into Rollback and synchronize there.
     public void destroyAppDataSnapshot(int rollbackId, PackageRollbackInfo packageRollbackInfo,
             int user) {
@@ -163,7 +162,7 @@
      *
      * @return true if any backups or restores were found for the userId
      */
-    @GuardedBy("rollback.getLock")
+    @GuardedBy("rollback.mLock")
     boolean commitPendingBackupAndRestoreForUser(int userId, Rollback rollback) {
         boolean foundBackupOrRestore = false;
         for (PackageRollbackInfo info : rollback.info.getPackages()) {
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index 2dc4951..1cf07cb 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -16,14 +16,34 @@
 
 package com.android.server.rollback;
 
+import static com.android.server.rollback.RollbackManagerServiceImpl.sendFailure;
+
+import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
+import android.os.Binder;
+import android.os.ParcelFileDescriptor;
+import android.os.UserManager;
+import android.util.IntArray;
+import android.util.Slog;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.text.ParseException;
@@ -34,17 +54,16 @@
 
 /**
  * Information about a rollback available for a set of atomically installed packages.
- *
- * <p>When accessing the state of a Rollback object, the caller is responsible for synchronization.
- * The lock object provided by {@link #getLock} should be acquired when accessing any of the mutable
- * state of a Rollback, including from the {@link RollbackInfo} and any of the
- * {@link PackageRollbackInfo} objects held within.
  */
 class Rollback {
+
+    private static final String TAG = "RollbackManager";
+
     @IntDef(flag = true, prefix = { "ROLLBACK_STATE_" }, value = {
             ROLLBACK_STATE_ENABLING,
             ROLLBACK_STATE_AVAILABLE,
             ROLLBACK_STATE_COMMITTED,
+            ROLLBACK_STATE_DELETED
     })
     @Retention(RetentionPolicy.SOURCE)
     @interface RollbackState {}
@@ -66,6 +85,11 @@
     static final int ROLLBACK_STATE_COMMITTED = 3;
 
     /**
+     * The rollback has been deleted.
+     */
+    static final int ROLLBACK_STATE_DELETED = 4;
+
+    /**
      * The session ID for the staged session if this rollback data represents a staged session,
      * {@code -1} otherwise.
      */
@@ -73,11 +97,7 @@
 
     /**
      * The rollback info for this rollback.
-     *
-     * <p>Any access to this field that touches any mutable state should be synchronized on
-     * {@link #getLock}.
      */
-    @GuardedBy("getLock")
     public final RollbackInfo info;
 
     /**
@@ -118,8 +138,6 @@
 
     /**
      * Lock object to guard all access to Rollback state.
-     *
-     * @see #getLock
      */
     private final Object mLock = new Object();
 
@@ -157,23 +175,8 @@
     }
 
     /**
-     * Returns a lock object that should be acquired before accessing any Rollback state from
-     * {@link RollbackManagerServiceImpl}.
-     *
-     * <p>Note that while holding this lock, the lock for {@link RollbackManagerServiceImpl} should
-     * not be acquired (but it is ok to acquire this lock while already holding the lock for that
-     * class).
-     */
-    // TODO(b/136241838): Move rollback functionality into this class and synchronize on the lock
-    // internally. Remove this method once this has been done for all cases.
-    Object getLock() {
-        return mLock;
-    }
-
-    /**
      * Whether the rollback is for rollback of a staged install.
      */
-    @GuardedBy("getLock")
     boolean isStaged() {
         return info.isStaged();
     }
@@ -188,17 +191,20 @@
     /**
      * Returns the time when the upgrade occurred, for purposes of expiring rollback data.
      */
-    @GuardedBy("getLock")
     Instant getTimestamp() {
-        return mTimestamp;
+        synchronized (mLock) {
+            return mTimestamp;
+        }
     }
 
     /**
      * Sets the time at which upgrade occurred.
      */
-    @GuardedBy("getLock")
     void setTimestamp(Instant timestamp) {
-        mTimestamp = timestamp;
+        synchronized (mLock) {
+            mTimestamp = timestamp;
+            RollbackStore.saveRollback(this);
+        }
     }
 
     /**
@@ -212,129 +218,444 @@
     /**
      * Returns true if the rollback is in the ENABLING state.
      */
-    @GuardedBy("getLock")
     boolean isEnabling() {
-        return mState == ROLLBACK_STATE_ENABLING;
+        synchronized (mLock) {
+            return mState == ROLLBACK_STATE_ENABLING;
+        }
     }
 
     /**
      * Returns true if the rollback is in the AVAILABLE state.
      */
-    @GuardedBy("getLock")
     boolean isAvailable() {
-        return mState == ROLLBACK_STATE_AVAILABLE;
+        synchronized (mLock) {
+            return mState == ROLLBACK_STATE_AVAILABLE;
+        }
     }
 
     /**
      * Returns true if the rollback is in the COMMITTED state.
      */
-    @GuardedBy("getLock")
     boolean isCommitted() {
-        return mState == ROLLBACK_STATE_COMMITTED;
+        synchronized (mLock) {
+            return mState == ROLLBACK_STATE_COMMITTED;
+        }
     }
 
     /**
-     * Sets the state of the rollback to AVAILABLE.
+     * Returns true if the rollback is in the DELETED state.
      */
-    @GuardedBy("getLock")
-    void setAvailable() {
-        mState = ROLLBACK_STATE_AVAILABLE;
+    boolean isDeleted() {
+        synchronized (mLock) {
+            return mState == ROLLBACK_STATE_DELETED;
+        }
     }
 
     /**
-     * Sets the state of the rollback to COMMITTED.
+     * Saves this rollback to persistent storage.
      */
-    @GuardedBy("getLock")
-    void setCommitted() {
-        mState = ROLLBACK_STATE_COMMITTED;
+    void saveRollback() {
+        synchronized (mLock) {
+            RollbackStore.saveRollback(this);
+        }
+    }
+
+    /**
+     * Enables this rollback for the provided package.
+     *
+     * @return boolean True if the rollback was enabled successfully for the specified package.
+     */
+    boolean enableForPackage(String packageName, long newVersion, long installedVersion,
+            boolean isApex, String sourceDir, String[] splitSourceDirs) {
+        try {
+            RollbackStore.backupPackageCodePath(this, packageName, sourceDir);
+            if (!ArrayUtils.isEmpty(splitSourceDirs)) {
+                for (String dir : splitSourceDirs) {
+                    RollbackStore.backupPackageCodePath(this, packageName, dir);
+                }
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e);
+            return false;
+        }
+
+        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
+                new VersionedPackage(packageName, newVersion),
+                new VersionedPackage(packageName, installedVersion),
+                new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
+                isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
+
+        synchronized (mLock) {
+            info.getPackages().add(packageRollbackInfo);
+        }
+
+        return true;
+    }
+
+    /**
+     * Snapshots user data for the provided package and user ids. Does nothing if this rollback is
+     * not in the ENABLING state.
+     */
+    void snapshotUserData(String packageName, int[] userIds, AppDataRollbackHelper dataHelper) {
+        synchronized (mLock) {
+            if (!isEnabling()) {
+                return;
+            }
+
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (pkgRollbackInfo.getPackageName().equals(packageName)) {
+                    dataHelper.snapshotAppData(info.getRollbackId(), pkgRollbackInfo, userIds);
+
+                    RollbackStore.saveRollback(this);
+                    pkgRollbackInfo.getSnapshottedUsers().addAll(IntArray.wrap(userIds));
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Commits the pending backups and restores for a given {@code userId}. If this rollback has a
+     * pending backup, it is updated with a mapping from {@code userId} to inode of the CE user data
+     * snapshot.
+     */
+    void commitPendingBackupAndRestoreForUser(int userId, AppDataRollbackHelper dataHelper) {
+        synchronized (mLock) {
+            if (dataHelper.commitPendingBackupAndRestoreForUser(userId, this)) {
+                RollbackStore.saveRollback(this);
+            }
+        }
+    }
+
+    /**
+     * Changes the state of the rollback to AVAILABLE. This also changes the timestamp to the
+     * current time and saves the rollback. Does nothing if this rollback is already in the
+     * DELETED state.
+     */
+    void makeAvailable() {
+        synchronized (mLock) {
+            if (isDeleted()) {
+                Slog.w(TAG, "Cannot make deleted rollback available.");
+                return;
+            }
+            mState = ROLLBACK_STATE_AVAILABLE;
+            mTimestamp = Instant.now();
+            RollbackStore.saveRollback(this);
+        }
+    }
+
+    /**
+     * Commits the rollback.
+     */
+    void commit(final Context context, List<VersionedPackage> causePackages,
+            String callerPackageName, IntentSender statusReceiver) {
+        synchronized (mLock) {
+            if (!isAvailable()) {
+                sendFailure(context, statusReceiver,
+                        RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
+                        "Rollback unavailable");
+                return;
+            }
+
+            // Get a context to use to install the downgraded version of the package.
+            Context pkgContext;
+            try {
+                pkgContext = context.createPackageContext(callerPackageName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
+                        "Invalid callerPackageName");
+                return;
+            }
+
+            PackageManager pm = pkgContext.getPackageManager();
+            try {
+                PackageInstaller packageInstaller = pm.getPackageInstaller();
+                PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
+                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+                parentParams.setRequestDowngrade(true);
+                parentParams.setMultiPackage();
+                if (isStaged()) {
+                    parentParams.setStaged();
+                }
+
+                int parentSessionId = packageInstaller.createSession(parentParams);
+                PackageInstaller.Session parentSession = packageInstaller.openSession(
+                        parentSessionId);
+
+                for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                    PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
+                            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+                    // TODO: We can't get the installerPackageName for apex
+                    // (b/123920130). Is it okay to ignore the installer package
+                    // for apex?
+                    if (!pkgRollbackInfo.isApex()) {
+                        String installerPackageName =
+                                pm.getInstallerPackageName(pkgRollbackInfo.getPackageName());
+                        if (installerPackageName != null) {
+                            params.setInstallerPackageName(installerPackageName);
+                        }
+                    }
+                    params.setRequestDowngrade(true);
+                    params.setRequiredInstalledVersionCode(
+                            pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode());
+                    if (isStaged()) {
+                        params.setStaged();
+                    }
+                    if (pkgRollbackInfo.isApex()) {
+                        params.setInstallAsApex();
+                    }
+                    int sessionId = packageInstaller.createSession(params);
+                    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
+                    File[] packageCodePaths = RollbackStore.getPackageCodePaths(
+                            this, pkgRollbackInfo.getPackageName());
+                    if (packageCodePaths == null) {
+                        sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
+                                "Backup copy of package inaccessible");
+                        return;
+                    }
+
+                    for (File packageCodePath : packageCodePaths) {
+                        try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath,
+                                ParcelFileDescriptor.MODE_READ_ONLY)) {
+                            final long token = Binder.clearCallingIdentity();
+                            try {
+                                session.write(packageCodePath.getName(), 0,
+                                        packageCodePath.length(),
+                                        fd);
+                            } finally {
+                                Binder.restoreCallingIdentity(token);
+                            }
+                        }
+                    }
+                    parentSession.addChildSessionId(sessionId);
+                }
+
+                final LocalIntentReceiver receiver = new LocalIntentReceiver(
+                        (Intent result) -> {
+                            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+                                    PackageInstaller.STATUS_FAILURE);
+                            if (status != PackageInstaller.STATUS_SUCCESS) {
+                                // Committing the rollback failed, but we still have all the info we
+                                // need to try rolling back again, so restore the rollback state to
+                                // how it was before we tried committing.
+                                // TODO: Should we just kill this rollback if commit failed?
+                                // Why would we expect commit not to fail again?
+                                // TODO: Could this cause a rollback to be resurrected
+                                // if it should otherwise have expired by now?
+                                synchronized (mLock) {
+                                    mState = ROLLBACK_STATE_AVAILABLE;
+                                    mRestoreUserDataInProgress = false;
+                                }
+                                sendFailure(context, statusReceiver,
+                                        RollbackManager.STATUS_FAILURE_INSTALL,
+                                        "Rollback downgrade install failed: "
+                                                + result.getStringExtra(
+                                                PackageInstaller.EXTRA_STATUS_MESSAGE));
+                                return;
+                            }
+
+                            synchronized (mLock) {
+                                if (!isStaged()) {
+                                    // All calls to restoreUserData should have
+                                    // completed by now for a non-staged install.
+                                    mRestoreUserDataInProgress = false;
+                                }
+
+                                info.setCommittedSessionId(parentSessionId);
+                                info.getCausePackages().addAll(causePackages);
+                                RollbackStore.deletePackageCodePaths(this);
+                                RollbackStore.saveRollback(this);
+                            }
+
+                            // Send success.
+                            try {
+                                final Intent fillIn = new Intent();
+                                fillIn.putExtra(
+                                        RollbackManager.EXTRA_STATUS,
+                                        RollbackManager.STATUS_SUCCESS);
+                                statusReceiver.sendIntent(context, 0, fillIn, null, null);
+                            } catch (IntentSender.SendIntentException e) {
+                                // Nowhere to send the result back to, so don't bother.
+                            }
+
+                            Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
+
+                            for (UserInfo userInfo : UserManager.get(context).getUsers(true)) {
+                                context.sendBroadcastAsUser(broadcast,
+                                        userInfo.getUserHandle(),
+                                        Manifest.permission.MANAGE_ROLLBACKS);
+                            }
+                        }
+                );
+
+                mState = ROLLBACK_STATE_COMMITTED;
+                mRestoreUserDataInProgress = true;
+                parentSession.commit(receiver.getIntentSender());
+            } catch (IOException e) {
+                Slog.e(TAG, "Rollback failed", e);
+                sendFailure(context, statusReceiver, RollbackManager.STATUS_FAILURE,
+                        "IOException: " + e.toString());
+            }
+        }
+    }
+
+    /**
+     * Restores user data for the specified package if this rollback is currently marked as
+     * having a restore in progress.
+     *
+     * @return boolean True if this rollback has a restore in progress and contains the specified
+     * package.
+     */
+    boolean restoreUserDataForPackageIfInProgress(String packageName, int[] userIds, int appId,
+            String seInfo, AppDataRollbackHelper dataHelper) {
+        synchronized (mLock) {
+            if (!isRestoreUserDataInProgress()) {
+                return false;
+            }
+
+            boolean foundPackage = false;
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (pkgRollbackInfo.getPackageName().equals(packageName)) {
+                    foundPackage = true;
+                    boolean changedRollback = false;
+                    for (int userId : userIds) {
+                        changedRollback |= dataHelper.restoreAppData(
+                                info.getRollbackId(), pkgRollbackInfo, userId, appId, seInfo);
+                    }
+                    // We've updated metadata about this rollback, so save it to flash.
+                    if (changedRollback) {
+                        RollbackStore.saveRollback(this);
+                    }
+                    break;
+                }
+            }
+            return foundPackage;
+        }
+    }
+
+    /**
+     * Deletes app data snapshots associated with this rollback, and moves to the DELETED state.
+     */
+    void delete(AppDataRollbackHelper dataHelper) {
+        synchronized (mLock) {
+            for (PackageRollbackInfo pkgInfo : info.getPackages()) {
+                IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers();
+                for (int i = 0; i < snapshottedUsers.size(); i++) {
+                    // Destroy app data snapshot.
+                    int userId = snapshottedUsers.get(i);
+
+                    dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId);
+                }
+            }
+
+            RollbackStore.deleteRollback(this);
+            mState = ROLLBACK_STATE_DELETED;
+        }
     }
 
     /**
      * Returns the id of the post-reboot apk session for a staged install, if any.
      */
-    @GuardedBy("getLock")
     int getApkSessionId() {
-        return mApkSessionId;
+        synchronized (mLock) {
+            return mApkSessionId;
+        }
     }
 
     /**
      * Sets the id of the post-reboot apk session for a staged install.
      */
-    @GuardedBy("getLock")
     void setApkSessionId(int apkSessionId) {
-        mApkSessionId = apkSessionId;
+        synchronized (mLock) {
+            mApkSessionId = apkSessionId;
+            RollbackStore.saveRollback(this);
+        }
     }
 
     /**
      * Returns true if we are expecting the package manager to call restoreUserData for this
      * rollback because it has just been committed but the rollback has not yet been fully applied.
      */
-    @GuardedBy("getLock")
     boolean isRestoreUserDataInProgress() {
-        return mRestoreUserDataInProgress;
+        synchronized (mLock) {
+            return mRestoreUserDataInProgress;
+        }
     }
 
     /**
      * Sets whether we are expecting the package manager to call restoreUserData for this
      * rollback because it has just been committed but the rollback has not yet been fully applied.
      */
-    @GuardedBy("getLock")
     void setRestoreUserDataInProgress(boolean restoreUserDataInProgress) {
-        mRestoreUserDataInProgress = restoreUserDataInProgress;
+        synchronized (mLock) {
+            mRestoreUserDataInProgress = restoreUserDataInProgress;
+            RollbackStore.saveRollback(this);
+        }
     }
 
     /**
      * Returns true if this rollback includes the package with the provided {@code packageName}.
      */
-    @GuardedBy("getLock")
     boolean includesPackage(String packageName) {
-        for (PackageRollbackInfo info : info.getPackages()) {
-            if (info.getPackageName().equals(packageName)) {
-                return true;
+        synchronized (mLock) {
+            for (PackageRollbackInfo packageRollbackInfo : info.getPackages()) {
+                if (packageRollbackInfo.getPackageName().equals(packageName)) {
+                    return true;
+                }
             }
+            return false;
         }
-        return false;
     }
 
     /**
      * Returns true if this rollback includes the package with the provided {@code packageName}
      * with a <i>version rolled back from</i> that is not {@code versionCode}.
      */
-    @GuardedBy("getLock")
     boolean includesPackageWithDifferentVersion(String packageName, long versionCode) {
-        for (PackageRollbackInfo info : info.getPackages()) {
-            if (info.getPackageName().equals(packageName)
-                    && info.getVersionRolledBackFrom().getLongVersionCode() != versionCode) {
-                return true;
+        synchronized (mLock) {
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (pkgRollbackInfo.getPackageName().equals(packageName)
+                        && pkgRollbackInfo.getVersionRolledBackFrom().getLongVersionCode()
+                        != versionCode) {
+                    return true;
+                }
             }
+            return false;
         }
-        return false;
     }
 
     /**
      * Returns a list containing the names of all the packages included in this rollback.
      */
-    @GuardedBy("getLock")
     List<String> getPackageNames() {
-        List<String> result = new ArrayList<>();
-        for (PackageRollbackInfo info : info.getPackages()) {
-            result.add(info.getPackageName());
+        synchronized (mLock) {
+            List<String> result = new ArrayList<>();
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                result.add(pkgRollbackInfo.getPackageName());
+            }
+            return result;
         }
-        return result;
     }
 
     /**
      * Returns a list containing the names of all the apex packages included in this rollback.
      */
-    @GuardedBy("getLock")
     List<String> getApexPackageNames() {
-        List<String> result = new ArrayList<>();
-        for (PackageRollbackInfo info : info.getPackages()) {
-            if (info.isApex()) {
-                result.add(info.getPackageName());
+        synchronized (mLock) {
+            List<String> result = new ArrayList<>();
+            for (PackageRollbackInfo pkgRollbackInfo : info.getPackages()) {
+                if (pkgRollbackInfo.isApex()) {
+                    result.add(pkgRollbackInfo.getPackageName());
+                }
             }
+            return result;
         }
-        return result;
+    }
+
+    int getPackageCount() {
+        synchronized (mLock) {
+            return info.getPackages().size();
+        }
     }
 
     static String rollbackStateToString(@RollbackState int state) {
@@ -356,8 +677,39 @@
         throw new ParseException("Invalid rollback state: " + state, 0);
     }
 
-    @GuardedBy("getLock")
     String getStateAsString() {
-        return rollbackStateToString(mState);
+        synchronized (mLock) {
+            return rollbackStateToString(mState);
+        }
+    }
+
+    void dump(IndentingPrintWriter ipw) {
+        synchronized (mLock) {
+            ipw.println(info.getRollbackId() + ":");
+            ipw.increaseIndent();
+            ipw.println("-state: " + getStateAsString());
+            ipw.println("-timestamp: " + getTimestamp());
+            if (getStagedSessionId() != -1) {
+                ipw.println("-stagedSessionId: " + getStagedSessionId());
+            }
+            ipw.println("-packages:");
+            ipw.increaseIndent();
+            for (PackageRollbackInfo pkg : info.getPackages()) {
+                ipw.println(pkg.getPackageName()
+                        + " " + pkg.getVersionRolledBackFrom().getLongVersionCode()
+                        + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
+            }
+            ipw.decreaseIndent();
+            if (isCommitted()) {
+                ipw.println("-causePackages:");
+                ipw.increaseIndent();
+                for (VersionedPackage cPkg : info.getCausePackages()) {
+                    ipw.println(cPkg.getPackageName() + " " + cPkg.getLongVersionCode());
+                }
+                ipw.decreaseIndent();
+                ipw.println("-committedSessionId: " + info.getCommittedSessionId());
+            }
+            ipw.decreaseIndent();
+        }
     }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index e8e448a..cd44f64 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -36,14 +36,12 @@
 import android.content.pm.UserInfo;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.IRollbackManager;
-import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -53,10 +51,8 @@
 import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
-import android.util.SparseLongArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
@@ -64,7 +60,6 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.security.SecureRandom;
 import java.time.Instant;
@@ -219,7 +214,7 @@
                     synchronized (mLock) {
                         for (NewRollback rollback : mNewRollbacks) {
                             if (rollback.hasToken(token)) {
-                                rollback.isCancelled = true;
+                                rollback.setCancelled();
                                 return;
                             }
                         }
@@ -282,10 +277,8 @@
             List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mRollbacks.size(); ++i) {
                 Rollback rollback = mRollbacks.get(i);
-                synchronized (rollback.getLock()) {
-                    if (rollback.isAvailable()) {
-                        rollbacks.add(rollback.info);
-                    }
+                if (rollback.isAvailable()) {
+                    rollbacks.add(rollback.info);
                 }
             }
             return new ParceledListSlice<>(rollbacks);
@@ -300,10 +293,8 @@
             List<RollbackInfo> rollbacks = new ArrayList<>();
             for (int i = 0; i < mRollbacks.size(); ++i) {
                 Rollback rollback = mRollbacks.get(i);
-                synchronized (rollback.getLock()) {
-                    if (rollback.isCommitted()) {
-                        rollbacks.add(rollback.info);
-                    }
+                if (rollback.isCommitted()) {
+                    rollbacks.add(rollback.info);
                 }
             }
             return new ParceledListSlice<>(rollbacks);
@@ -336,11 +327,8 @@
                     Iterator<Rollback> iter = mRollbacks.iterator();
                     while (iter.hasNext()) {
                         Rollback rollback = iter.next();
-                        synchronized (rollback.getLock()) {
-                            rollback.setTimestamp(
-                                    rollback.getTimestamp().plusMillis(timeDifference));
-                            saveRollback(rollback);
-                        }
+                        rollback.setTimestamp(
+                                rollback.getTimestamp().plusMillis(timeDifference));
                     }
                 }
             }
@@ -366,155 +354,12 @@
 
         Rollback rollback = getRollbackForId(rollbackId);
         if (rollback == null) {
-            sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
+            sendFailure(
+                    mContext, statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
                     "Rollback unavailable");
             return;
         }
-        synchronized (rollback.getLock()) {
-            if (!rollback.isAvailable()) {
-                sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE,
-                        "Rollback unavailable");
-                return;
-            }
-
-            // Get a context for the caller to use to install the downgraded
-            // version of the package.
-            final Context context;
-            try {
-                context = mContext.createPackageContext(callerPackageName, 0);
-            } catch (PackageManager.NameNotFoundException e) {
-                sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
-                        "Invalid callerPackageName");
-                return;
-            }
-
-            PackageManager pm = context.getPackageManager();
-            try {
-                PackageInstaller packageInstaller = pm.getPackageInstaller();
-                PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
-                        PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-                parentParams.setRequestDowngrade(true);
-                parentParams.setMultiPackage();
-                if (rollback.isStaged()) {
-                    parentParams.setStaged();
-                }
-
-                int parentSessionId = packageInstaller.createSession(parentParams);
-                PackageInstaller.Session parentSession = packageInstaller.openSession(
-                        parentSessionId);
-
-                for (PackageRollbackInfo info : rollback.info.getPackages()) {
-                    PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
-                            PackageInstaller.SessionParams.MODE_FULL_INSTALL);
-                    // TODO: We can't get the installerPackageName for apex
-                    // (b/123920130). Is it okay to ignore the installer package
-                    // for apex?
-                    if (!info.isApex()) {
-                        String installerPackageName =
-                                pm.getInstallerPackageName(info.getPackageName());
-                        if (installerPackageName != null) {
-                            params.setInstallerPackageName(installerPackageName);
-                        }
-                    }
-                    params.setRequestDowngrade(true);
-                    params.setRequiredInstalledVersionCode(
-                            info.getVersionRolledBackFrom().getLongVersionCode());
-                    if (rollback.isStaged()) {
-                        params.setStaged();
-                    }
-                    if (info.isApex()) {
-                        params.setInstallAsApex();
-                    }
-                    int sessionId = packageInstaller.createSession(params);
-                    PackageInstaller.Session session = packageInstaller.openSession(sessionId);
-                    File[] packageCodePaths = RollbackStore.getPackageCodePaths(
-                            rollback, info.getPackageName());
-                    if (packageCodePaths == null) {
-                        sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
-                                "Backup copy of package inaccessible");
-                        return;
-                    }
-
-                    for (File packageCodePath : packageCodePaths) {
-                        try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(packageCodePath,
-                                ParcelFileDescriptor.MODE_READ_ONLY)) {
-                            final long token = Binder.clearCallingIdentity();
-                            try {
-                                session.write(packageCodePath.getName(), 0,
-                                        packageCodePath.length(),
-                                        fd);
-                            } finally {
-                                Binder.restoreCallingIdentity(token);
-                            }
-                        }
-                    }
-                    parentSession.addChildSessionId(sessionId);
-                }
-
-                final LocalIntentReceiver receiver = new LocalIntentReceiver(
-                        (Intent result) -> getHandler().post(() -> {
-
-                            int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
-                                    PackageInstaller.STATUS_FAILURE);
-                            if (status != PackageInstaller.STATUS_SUCCESS) {
-                                // Committing the rollback failed, but we
-                                // still have all the info we need to try
-                                // rolling back again, so restore the rollback
-                                // state to how it was before we tried
-                                // committing.
-                                // TODO: Should we just kill this rollback if
-                                // commit failed? Why would we expect commit
-                                // not to fail again?
-                                // TODO: Could this cause a rollback to be
-                                // resurrected if it should otherwise have
-                                // expired by now?
-                                synchronized (rollback.getLock()) {
-                                    rollback.setAvailable();
-                                    rollback.setRestoreUserDataInProgress(false);
-                                }
-                                sendFailure(statusReceiver,
-                                        RollbackManager.STATUS_FAILURE_INSTALL,
-                                        "Rollback downgrade install failed: "
-                                                + result.getStringExtra(
-                                                PackageInstaller.EXTRA_STATUS_MESSAGE));
-                                return;
-                            }
-
-                            synchronized (rollback.getLock()) {
-                                if (!rollback.isStaged()) {
-                                    // All calls to restoreUserData should have
-                                    // completed by now for a non-staged install.
-                                    rollback.setRestoreUserDataInProgress(false);
-                                }
-
-                                rollback.info.setCommittedSessionId(parentSessionId);
-                                rollback.info.getCausePackages().addAll(causePackages);
-                                RollbackStore.deletePackageCodePaths(rollback);
-                                saveRollback(rollback);
-                            }
-
-                            sendSuccess(statusReceiver);
-
-                            Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
-
-                            for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
-                                mContext.sendBroadcastAsUser(broadcast,
-                                        userInfo.getUserHandle(),
-                                        Manifest.permission.MANAGE_ROLLBACKS);
-                            }
-                        })
-                );
-
-                rollback.setCommitted();
-                rollback.setRestoreUserDataInProgress(true);
-                parentSession.commit(receiver.getIntentSender());
-            } catch (IOException e) {
-                Slog.e(TAG, "Rollback failed", e);
-                sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
-                        "IOException: " + e.toString());
-                return;
-            }
-        }
+        rollback.commit(mContext, causePackages, callerPackageName, statusReceiver);
     }
 
     @Override
@@ -549,18 +394,14 @@
             Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
                 Rollback rollback = iter.next();
-                synchronized (rollback.getLock()) {
-                    if (rollback.includesPackage(packageName)) {
-                        iter.remove();
-                        deleteRollback(rollback);
-                    }
+                if (rollback.includesPackage(packageName)) {
+                    iter.remove();
+                    rollback.delete(mAppDataRollbackHelper);
                 }
             }
             for (NewRollback newRollback : mNewRollbacks) {
-                synchronized (newRollback.rollback.getLock()) {
-                    if (newRollback.rollback.includesPackage(packageName)) {
-                        newRollback.isCancelled = true;
-                    }
+                if (newRollback.rollback.includesPackage(packageName)) {
+                    newRollback.setCancelled();
                 }
             }
         }
@@ -593,12 +434,7 @@
 
             for (int i = 0; i < rollbacks.size(); i++) {
                 Rollback rollback = rollbacks.get(i);
-                synchronized (rollback.getLock()) {
-                    if (mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(
-                            userId, rollback)) {
-                        saveRollback(rollback);
-                    }
-                }
+                rollback.commitPendingBackupAndRestoreForUser(userId, mAppDataRollbackHelper);
             }
 
             latch.countDown();
@@ -634,48 +470,41 @@
             Set<String> apexPackageNames = new HashSet<>();
             synchronized (mLock) {
                 for (Rollback rollback : mRollbacks) {
-                    synchronized (rollback.getLock()) {
-                        if (rollback.isStaged()) {
-                            if (rollback.isEnabling()) {
-                                enabling.add(rollback);
-                            } else if (rollback.isRestoreUserDataInProgress()) {
-                                restoreInProgress.add(rollback);
-                            }
-
-                            apexPackageNames.addAll(rollback.getApexPackageNames());
+                    if (rollback.isStaged()) {
+                        if (rollback.isEnabling()) {
+                            enabling.add(rollback);
+                        } else if (rollback.isRestoreUserDataInProgress()) {
+                            restoreInProgress.add(rollback);
                         }
+
+                        apexPackageNames.addAll(rollback.getApexPackageNames());
                     }
                 }
             }
 
             for (Rollback rollback : enabling) {
                 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
-                synchronized (rollback.getLock()) {
-                    PackageInstaller.SessionInfo session =
-                            installer.getSessionInfo(rollback.getStagedSessionId());
-                    if (session == null || session.isStagedSessionFailed()) {
-                        // TODO: Do we need to remove this from
-                        // mRollbacks, or is it okay to leave as
-                        // unavailable until the next reboot when it will go
-                        // away on its own?
-                        deleteRollback(rollback);
-                    } else if (session.isStagedSessionApplied()) {
-                        makeRollbackAvailable(rollback);
-                    }
+                PackageInstaller.SessionInfo session =
+                        installer.getSessionInfo(rollback.getStagedSessionId());
+                if (session == null || session.isStagedSessionFailed()) {
+                    // TODO: Do we need to remove this from
+                    // mRollbacks, or is it okay to leave as
+                    // unavailable until the next reboot when it will go
+                    // away on its own?
+                    rollback.delete(mAppDataRollbackHelper);
+                } else if (session.isStagedSessionApplied()) {
+                    makeRollbackAvailable(rollback);
                 }
             }
 
             for (Rollback rollback : restoreInProgress) {
                 PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
-                synchronized (rollback.getLock()) {
-                    PackageInstaller.SessionInfo session =
-                            installer.getSessionInfo(rollback.getStagedSessionId());
-                    // TODO: What if session is null?
-                    if (session != null) {
-                        if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
-                            rollback.setRestoreUserDataInProgress(false);
-                            saveRollback(rollback);
-                        }
+                PackageInstaller.SessionInfo session =
+                        installer.getSessionInfo(rollback.getStagedSessionId());
+                // TODO: What if session is null?
+                if (session != null) {
+                    if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) {
+                        rollback.setRestoreUserDataInProgress(false);
                     }
                 }
             }
@@ -710,14 +539,12 @@
             Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
                 Rollback rollback = iter.next();
-                synchronized (rollback.getLock()) {
-                    // TODO: Should we remove rollbacks in the ENABLING state here?
-                    if ((rollback.isEnabling() || rollback.isAvailable())
-                            && rollback.includesPackageWithDifferentVersion(packageName,
-                            installedVersion)) {
-                        iter.remove();
-                        deleteRollback(rollback);
-                    }
+                // TODO: Should we remove rollbacks in the ENABLING state here?
+                if ((rollback.isEnabling() || rollback.isAvailable())
+                        && rollback.includesPackageWithDifferentVersion(packageName,
+                        installedVersion)) {
+                    iter.remove();
+                    rollback.delete(mAppDataRollbackHelper);
                 }
             }
         }
@@ -738,27 +565,14 @@
      * @param status the RollbackManager.STATUS_* code with the failure.
      * @param message the failure message.
      */
-    private void sendFailure(IntentSender statusReceiver, @RollbackManager.Status int status,
-            String message) {
+    static void sendFailure(Context context, IntentSender statusReceiver,
+            @RollbackManager.Status int status, String message) {
         Slog.e(TAG, message);
         try {
             final Intent fillIn = new Intent();
             fillIn.putExtra(RollbackManager.EXTRA_STATUS, status);
             fillIn.putExtra(RollbackManager.EXTRA_STATUS_MESSAGE, message);
-            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
-        } catch (IntentSender.SendIntentException e) {
-            // Nowhere to send the result back to, so don't bother.
-        }
-    }
-
-    /**
-     * Notifies an IntentSender of success.
-     */
-    private void sendSuccess(IntentSender statusReceiver) {
-        try {
-            final Intent fillIn = new Intent();
-            fillIn.putExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_SUCCESS);
-            statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+            statusReceiver.sendIntent(context, 0, fillIn, null, null);
         } catch (IntentSender.SendIntentException e) {
             // Nowhere to send the result back to, so don't bother.
         }
@@ -773,18 +587,17 @@
             Iterator<Rollback> iter = mRollbacks.iterator();
             while (iter.hasNext()) {
                 Rollback rollback = iter.next();
-                synchronized (rollback.getLock()) {
-                    if (!rollback.isAvailable()) {
-                        continue;
-                    }
-                    if (!now.isBefore(
-                            rollback.getTimestamp()
-                                    .plusMillis(mRollbackLifetimeDurationInMillis))) {
-                        iter.remove();
-                        deleteRollback(rollback);
-                    } else if (oldest == null || oldest.isAfter(rollback.getTimestamp())) {
-                        oldest = rollback.getTimestamp();
-                    }
+                if (!rollback.isAvailable()) {
+                    continue;
+                }
+                Instant rollbackTimestamp = rollback.getTimestamp();
+                if (!now.isBefore(
+                        rollbackTimestamp
+                                .plusMillis(mRollbackLifetimeDurationInMillis))) {
+                    iter.remove();
+                    rollback.delete(mAppDataRollbackHelper);
+                } else if (oldest == null || oldest.isAfter(rollbackTimestamp)) {
+                    oldest = rollbackTimestamp;
                 }
             }
         }
@@ -892,12 +705,10 @@
         synchronized (mLock) {
             for (int i = 0; i < mRollbacks.size(); ++i) {
                 Rollback rollback = mRollbacks.get(i);
-                synchronized (rollback.getLock()) {
-                    if (rollback.getApkSessionId() == parentSession.getSessionId()) {
-                        // This is the apk session for a staged session with rollback enabled. We do
-                        // not need to create a new rollback for this session.
-                        return true;
-                    }
+                if (rollback.getApkSessionId() == parentSession.getSessionId()) {
+                    // This is the apk session for a staged session with rollback enabled. We do
+                    // not need to create a new rollback for this session.
+                    return true;
                 }
             }
         }
@@ -954,7 +765,7 @@
         }
 
         // Get information about the package to be installed.
-        PackageParser.PackageLite newPackage = null;
+        PackageParser.PackageLite newPackage;
         try {
             newPackage = PackageParser.parsePackageLite(new File(session.resolvedBaseCodePath), 0);
         } catch (PackageParser.PackageParserException e) {
@@ -973,11 +784,9 @@
             return false;
         }
 
-        VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
         final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
 
         // Get information about the currently installed package.
-        PackageManager pm = mContext.getPackageManager();
         final PackageInfo pkgInfo;
         try {
             pkgInfo = getPackageInfo(packageName);
@@ -988,32 +797,10 @@
             return false;
         }
 
-        VersionedPackage installedVersion = new VersionedPackage(packageName,
-                pkgInfo.getLongVersionCode());
-
-        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(
-                newVersion, installedVersion,
-                new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
-                isApex, new IntArray(), new SparseLongArray() /* ceSnapshotInodes */);
-
-
-        try {
-            ApplicationInfo appInfo = pkgInfo.applicationInfo;
-            RollbackStore.backupPackageCodePath(rollback, packageName, appInfo.sourceDir);
-            if (!ArrayUtils.isEmpty(appInfo.splitSourceDirs)) {
-                for (String sourceDir : appInfo.splitSourceDirs) {
-                    RollbackStore.backupPackageCodePath(rollback, packageName, sourceDir);
-                }
-            }
-        } catch (IOException e) {
-            Slog.e(TAG, "Unable to copy package for rollback for " + packageName, e);
-            return false;
-        }
-
-        synchronized (rollback.getLock()) {
-            rollback.info.getPackages().add(packageRollbackInfo);
-        }
-        return true;
+        ApplicationInfo appInfo = pkgInfo.applicationInfo;
+        return rollback.enableForPackage(packageName, newPackage.versionCode,
+                pkgInfo.getLongVersionCode(), isApex, appInfo.sourceDir,
+                appInfo.splitSourceDirs);
     }
 
     @Override
@@ -1026,7 +813,7 @@
 
         getHandler().post(() -> {
             snapshotUserDataInternal(packageName, userIds);
-            restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
+            restoreUserDataInternal(packageName, userIds, appId, seInfo);
             final PackageManagerInternal pmi = LocalServices.getService(
                     PackageManagerInternal.class);
             pmi.finishPackageInstall(token, false);
@@ -1038,67 +825,24 @@
             // staged installs
             for (int i = 0; i < mRollbacks.size(); i++) {
                 Rollback rollback = mRollbacks.get(i);
-                synchronized (rollback.getLock()) {
-                    if (!rollback.isEnabling()) {
-                        continue;
-                    }
-
-                    for (PackageRollbackInfo info : rollback.info.getPackages()) {
-                        if (info.getPackageName().equals(packageName)) {
-                            mAppDataRollbackHelper.snapshotAppData(
-                                    rollback.info.getRollbackId(), info, userIds);
-                            saveRollback(rollback);
-                            break;
-                        }
-                    }
-                }
+                rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
             }
             // non-staged installs
-            PackageRollbackInfo info;
             for (NewRollback rollback : mNewRollbacks) {
-                synchronized (rollback.rollback.getLock()) {
-                    info = getPackageRollbackInfo(rollback.rollback, packageName);
-                    if (info != null) {
-                        mAppDataRollbackHelper.snapshotAppData(
-                                rollback.rollback.info.getRollbackId(), info, userIds);
-                        saveRollback(rollback.rollback);
-                    }
-                }
+                rollback.rollback.snapshotUserData(
+                        packageName, userIds, mAppDataRollbackHelper);
             }
         }
     }
 
-    private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
-            long ceDataInode, String seInfo, int token) {
-        PackageRollbackInfo info = null;
-        Rollback rollback = null;
+    private void restoreUserDataInternal(
+            String packageName, int[] userIds, int appId, String seInfo) {
         synchronized (mLock) {
             for (int i = 0; i < mRollbacks.size(); ++i) {
-                Rollback candidate = mRollbacks.get(i);
-                synchronized (candidate.getLock()) {
-                    if (candidate.isRestoreUserDataInProgress()) {
-                        info = getPackageRollbackInfo(candidate, packageName);
-                        if (info != null) {
-                            rollback = candidate;
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        if (rollback == null) {
-            return;
-        }
-
-        for (int userId : userIds) {
-            synchronized (rollback.getLock()) {
-                final boolean changedRollback = mAppDataRollbackHelper.restoreAppData(
-                        rollback.info.getRollbackId(), info, userId, appId, seInfo);
-
-                // We've updated metadata about this rollback, so save it to flash.
-                if (changedRollback) {
-                    saveRollback(rollback);
+                Rollback rollback = mRollbacks.get(i);
+                if (rollback.restoreUserDataForPackageIfInProgress(
+                        packageName, userIds, appId, seInfo, mAppDataRollbackHelper)) {
+                    return;
                 }
             }
         }
@@ -1187,10 +931,7 @@
             }
 
             if (rollback != null) {
-                synchronized (rollback.getLock()) {
-                    rollback.setApkSessionId(apkSessionId);
-                    saveRollback(rollback);
-                }
+                rollback.setApkSessionId(apkSessionId);
             }
         });
     }
@@ -1238,8 +979,7 @@
      * Returns -1 if the package is not currently installed.
      */
     private long getInstalledPackageVersion(String packageName) {
-        PackageManager pm = mContext.getPackageManager();
-        PackageInfo pkgInfo = null;
+        PackageInfo pkgInfo;
         try {
             pkgInfo = getPackageInfo(packageName);
         } catch (PackageManager.NameNotFoundException e) {
@@ -1250,9 +990,9 @@
     }
 
     /**
-     * Gets PackageInfo for the given package.
-     * Matches any user and apex. Returns null if no such package is
-     * installed.
+     * Gets PackageInfo for the given package. Matches any user and apex.
+     *
+     * @throws PackageManager.NameNotFoundException if no such package is installed.
      */
     private PackageInfo getPackageInfo(String packageName)
             throws PackageManager.NameNotFoundException {
@@ -1268,13 +1008,6 @@
         }
     }
 
-
-    private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
-        return a != null && b != null
-            && a.getPackageName().equals(b.getPackageName())
-            && a.getLongVersionCode() == b.getLongVersionCode();
-    }
-
     private class SessionCallback extends PackageInstaller.SessionCallback {
 
         @Override
@@ -1301,12 +1034,8 @@
 
             if (newRollback != null) {
                 Rollback rollback = completeEnableRollback(newRollback, success);
-                if (rollback != null) {
-                    synchronized (rollback.getLock()) {
-                        if (!rollback.isStaged()) {
-                            makeRollbackAvailable(rollback);
-                        }
-                    }
+                if (rollback != null && !rollback.isStaged()) {
+                    makeRollbackAvailable(rollback);
                 }
             }
         }
@@ -1316,34 +1045,30 @@
      * Add a rollback to the list of rollbacks. This should be called after rollback has been
      * enabled for all packages in the rollback. It does not make the rollback available yet.
      *
-     * <p>Note that no rollback-specific locks should be held when this method is called.
-     *
      * @return the Rollback instance for a successfully enable-completed rollback,
      * or null on error.
      */
     private Rollback completeEnableRollback(NewRollback newRollback, boolean success) {
         Rollback rollback = newRollback.rollback;
-        synchronized (rollback.getLock()) {
-            if (!success) {
-                // The install session was aborted, clean up the pending install.
-                deleteRollback(rollback);
-                return null;
-            }
-            if (newRollback.isCancelled) {
-                Slog.e(TAG, "Rollback has been cancelled by PackageManager");
-                deleteRollback(rollback);
-                return null;
-            }
-
-
-            if (rollback.info.getPackages().size() != newRollback.packageSessionIds.length) {
-                Slog.e(TAG, "Failed to enable rollback for all packages in session.");
-                deleteRollback(rollback);
-                return null;
-            }
-
-            saveRollback(rollback);
+        if (!success) {
+            // The install session was aborted, clean up the pending install.
+            rollback.delete(mAppDataRollbackHelper);
+            return null;
         }
+
+        if (newRollback.isCancelled()) {
+            Slog.e(TAG, "Rollback has been cancelled by PackageManager");
+            rollback.delete(mAppDataRollbackHelper);
+            return null;
+        }
+
+        if (rollback.getPackageCount() != newRollback.getPackageSessionIdCount()) {
+            Slog.e(TAG, "Failed to enable rollback for all packages in session.");
+            rollback.delete(mAppDataRollbackHelper);
+            return null;
+        }
+
+        rollback.saveRollback();
         synchronized (mLock) {
             // Note: There is a small window of time between when
             // the session has been committed by the package
@@ -1363,17 +1088,12 @@
 
     @GuardedBy("rollback.getLock")
     private void makeRollbackAvailable(Rollback rollback) {
-        // TODO: What if the rollback has since been expired, for example due
-        // to a new package being installed. Won't this revive an expired
-        // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this.
-        rollback.setAvailable();
-        rollback.setTimestamp(Instant.now());
-        saveRollback(rollback);
+        rollback.makeAvailable();
 
         // TODO(zezeozue): Provide API to explicitly start observing instead
         // of doing this for all rollbacks. If we do this for all rollbacks,
         // should document in PackageInstaller.SessionParams#setEnableRollback
-        // After enabling and commiting any rollback, observe packages and
+        // After enabling and committing any rollback, observe packages and
         // prepare to rollback if packages crashes too frequently.
         mPackageHealthObserver.startObservingHealth(rollback.getPackageNames(),
                 mRollbackLifetimeDurationInMillis);
@@ -1396,22 +1116,6 @@
         return null;
     }
 
-    /**
-     * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
-     * a specified {@code Rollback}.
-     */
-    @GuardedBy("rollback.getLock")
-    private static PackageRollbackInfo getPackageRollbackInfo(Rollback rollback,
-            String packageName) {
-        for (PackageRollbackInfo info : rollback.info.getPackages()) {
-            if (info.getPackageName().equals(packageName)) {
-                return info;
-            }
-        }
-
-        return null;
-    }
-
     @GuardedBy("mLock")
     private int allocateRollbackIdLocked() {
         int n = 0;
@@ -1427,68 +1131,12 @@
         throw new IllegalStateException("Failed to allocate rollback ID");
     }
 
-    @GuardedBy("rollback.getLock")
-    private void deleteRollback(Rollback rollback) {
-        for (PackageRollbackInfo info : rollback.info.getPackages()) {
-            IntArray snapshottedUsers = info.getSnapshottedUsers();
-            for (int i = 0; i < snapshottedUsers.size(); i++) {
-                int userId = snapshottedUsers.get(i);
-                mAppDataRollbackHelper.destroyAppDataSnapshot(rollback.info.getRollbackId(),
-                        info, userId);
-            }
-        }
-        mRollbackStore.deleteRollback(rollback);
-    }
-
-    /**
-     * Saves a rollback, swallowing any IOExceptions.
-     * For those times when it's not obvious what to do about the IOException.
-     * TODO: Double check we can't do a better job handling the IOException in
-     * a cases where this method is called.
-     */
-    @GuardedBy("rollback.getLock")
-    private void saveRollback(Rollback rollback) {
-        try {
-            mRollbackStore.saveRollback(rollback);
-        } catch (IOException ioe) {
-            Slog.e(TAG, "Unable to save rollback for: "
-                    + rollback.info.getRollbackId(), ioe);
-        }
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
         synchronized (mLock) {
             for (Rollback rollback : mRollbacks) {
-                synchronized (rollback.getLock()) {
-                    RollbackInfo info = rollback.info;
-                    ipw.println(info.getRollbackId() + ":");
-                    ipw.increaseIndent();
-                    ipw.println("-state: " + rollback.getStateAsString());
-                    ipw.println("-timestamp: " + rollback.getTimestamp());
-                    if (rollback.getStagedSessionId() != -1) {
-                        ipw.println("-stagedSessionId: " + rollback.getStagedSessionId());
-                    }
-                    ipw.println("-packages:");
-                    ipw.increaseIndent();
-                    for (PackageRollbackInfo pkg : info.getPackages()) {
-                        ipw.println(pkg.getPackageName()
-                                + " " + pkg.getVersionRolledBackFrom().getLongVersionCode()
-                                + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode());
-                    }
-                    ipw.decreaseIndent();
-                    if (rollback.isCommitted()) {
-                        ipw.println("-causePackages:");
-                        ipw.increaseIndent();
-                        for (VersionedPackage cPkg : info.getCausePackages()) {
-                            ipw.println(cPkg.getPackageName() + " " + cPkg.getLongVersionCode());
-                        }
-                        ipw.decreaseIndent();
-                        ipw.println("-committedSessionId: " + info.getCommittedSessionId());
-                    }
-                    ipw.decreaseIndent();
-                }
+                rollback.dump(ipw);
             }
         }
     }
@@ -1508,22 +1156,51 @@
         public final Rollback rollback;
 
         /**
-         * This array holds all of the rollback tokens associated with package sessions included
-         * in this rollback. This is used to identify which rollback should be cancelled in case
-         * {@link PackageManager} sends an {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} intent.
+         * This array holds all of the rollback tokens associated with package sessions included in
+         * this rollback.
          */
+        @GuardedBy("mNewRollbackLock")
         private final IntArray mTokens = new IntArray();
 
         /**
-         * Session ids for all packages in the install.
-         * For multi-package sessions, this is the list of child session ids.
-         * For normal sessions, this list is a single element with the normal
+         * Session ids for all packages in the install. For multi-package sessions, this is the list
+         * of child session ids. For normal sessions, this list is a single element with the normal
          * session id.
          */
-        public final int[] packageSessionIds;
+        private final int[] mPackageSessionIds;
+
+        @GuardedBy("mNewRollbackLock")
+        private boolean mIsCancelled = false;
+
+        private final Object mNewRollbackLock = new Object();
+
+        NewRollback(Rollback rollback, int[] packageSessionIds) {
+            this.rollback = rollback;
+            this.mPackageSessionIds = packageSessionIds;
+        }
 
         /**
-         * Flag to determine whether the rollback has been cancelled.
+         * Adds a rollback token to be associated with this NewRollback. This may be used to
+         * identify which rollback should be cancelled in case {@link PackageManager} sends an
+         * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} intent.
+         */
+        void addToken(int token) {
+            synchronized (mNewRollbackLock) {
+                mTokens.add(token);
+            }
+        }
+
+        /**
+         * Returns true if this NewRollback is associated with the provided {@code token}.
+         */
+        boolean hasToken(int token) {
+            synchronized (mNewRollbackLock) {
+                return mTokens.indexOf(token) != -1;
+            }
+        }
+
+        /**
+         * Returns true if this NewRollback has been cancelled.
          *
          * <p>Rollback could be invalidated and cancelled if RollbackManager receives
          * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK} from {@link PackageManager}.
@@ -1533,19 +1210,38 @@
          * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)} before it broadcasts
          * {@link Intent#ACTION_CANCEL_ENABLE_ROLLBACK}.
          */
-        public boolean isCancelled = false;
-
-        NewRollback(Rollback rollback, int[] packageSessionIds) {
-            this.rollback = rollback;
-            this.packageSessionIds = packageSessionIds;
+        boolean isCancelled() {
+            synchronized (mNewRollbackLock) {
+                return mIsCancelled;
+            }
         }
 
-        public void addToken(int token) {
-            mTokens.add(token);
+        /**
+         * Sets this NewRollback to be marked as cancelled.
+         */
+        void setCancelled() {
+            synchronized (mNewRollbackLock) {
+                mIsCancelled = true;
+            }
         }
 
-        public boolean hasToken(int token) {
-            return mTokens.indexOf(token) != -1;
+        /**
+         * Returns true if this NewRollback contains the provided {@code packageSessionId}.
+         */
+        boolean containsSessionId(int packageSessionId) {
+            for (int id : mPackageSessionIds) {
+                if (id == packageSessionId) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the number of package session ids in this NewRollback.
+         */
+        int getPackageSessionIdCount() {
+            return mPackageSessionIds.length;
         }
     }
 
@@ -1576,14 +1272,13 @@
      * Returns null if no NewRollback is found for the given package
      * session.
      */
+    @GuardedBy("mLock")
     NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
         // We expect mNewRollbacks to be a very small list; linear search
         // should be plenty fast.
         for (NewRollback newRollback: mNewRollbacks) {
-            for (int id : newRollback.packageSessionIds) {
-                if (id == packageSessionId) {
-                    return newRollback;
-                }
+            if (newRollback.containsSessionId(packageSessionId)) {
+                return newRollback;
             }
         }
         return null;
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index b6d1f18..eadd09c 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -252,8 +252,8 @@
     /**
      * Saves the given rollback to persistent storage.
      */
-    @GuardedBy("rollback.getLock")
-    void saveRollback(Rollback rollback) throws IOException {
+    @GuardedBy("rollback.mLock")
+    static void saveRollback(Rollback rollback) {
         try {
             JSONObject dataJson = new JSONObject();
             dataJson.put("info", rollbackInfoToJson(rollback.info));
@@ -266,15 +266,15 @@
             PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json"));
             pw.println(dataJson.toString());
             pw.close();
-        } catch (JSONException e) {
-            throw new IOException(e);
+        } catch (JSONException | IOException e) {
+            Slog.e(TAG, "Unable to save rollback for: " + rollback.info.getRollbackId(), e);
         }
     }
 
     /**
      * Removes all persistent storage associated with the given rollback.
      */
-    void deleteRollback(Rollback rollback) {
+    static void deleteRollback(Rollback rollback) {
         removeFile(rollback.getBackupDir());
     }
 
diff --git a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
index 2b25b89..8431ae4 100644
--- a/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
+++ b/services/core/java/com/android/server/stats/ProcfsMemoryUtil.java
@@ -72,6 +72,30 @@
         return null;
     }
 
+    /**
+     * Reads cmdline of a process from procfs.
+     *
+     * Returns content of /proc/pid/cmdline (e.g. /system/bin/statsd) or an empty string
+     * if the file is not available.
+     */
+    public static String readCmdlineFromProcfs(int pid) {
+        return parseCmdline(readFile("/proc/" + pid + "/cmdline"));
+    }
+
+    /**
+     * Parses cmdline out of the contents of the /proc/pid/cmdline file in procfs.
+     *
+     * Parsing is required to strip anything after the first null byte.
+     */
+    @VisibleForTesting
+    static String parseCmdline(String contents) {
+        int firstNullByte = contents.indexOf("\0");
+        if (firstNullByte == -1) {
+            return contents;
+        }
+        return contents.substring(0, firstNullByte);
+    }
+
     private static String readFile(String path) {
         try {
             final File file = new File(path);
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index e488cc9..9d9a37c 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -50,9 +50,9 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.RootActivityContainer.FindTaskResult;
 import static com.android.server.wm.RootActivityContainer.TAG_STATES;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 
@@ -76,6 +76,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.am.EventLogTags;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -84,8 +85,7 @@
  * Exactly one of these classes per Display in the system. Capable of holding zero or more
  * attached {@link ActivityStack}s.
  */
-class ActivityDisplay extends ConfigurationContainer<ActivityStack>
-        implements WindowContainerListener {
+class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
     private static final String TAG_STACK = TAG + POSTFIX_STACK;
 
@@ -201,11 +201,6 @@
         }
     }
 
-    @Override
-    public void onInitializeOverrideConfiguration(Configuration config) {
-        getRequestedOverrideConfiguration().updateFrom(config);
-    }
-
     void addChild(ActivityStack stack, int position) {
         if (position == POSITION_BOTTOM) {
             position = 0;
@@ -291,9 +286,7 @@
         }
 
         // Since positionChildAt() is called during the creation process of pinned stacks,
-        // ActivityStack#getStack() can be null. In this special case,
-        // since DisplayContest#positionStackAt() is called in TaskStack#onConfigurationChanged(),
-        // we don't have to call WindowContainerController#positionChildAt() here.
+        // ActivityStack#getStack() can be null.
         if (stack.getTaskStack() != null && mDisplayContent != null) {
             mDisplayContent.positionStackAt(insertPosition,
                     stack.getTaskStack(), includingParents);
@@ -1202,8 +1195,8 @@
         // Stacks could be reparented from the removed display to other display. While
         // reparenting the last stack of the removed display, the remove display is ready to be
         // released (no more ActivityStack). But, we cannot release it at that moment or the
-        // related WindowContainer and WindowContainerController will also be removed. So, we
-        // set display as removed after reparenting stack finished.
+        // related WindowContainer will also be removed. So, we set display as removed after
+        // reparenting stack finished.
         final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
         mRootActivityContainer.mStackSupervisor.beginDeferResume();
         try {
@@ -1304,8 +1297,8 @@
         final AppWindowToken newFocus;
         final IBinder token = r.appToken;
         if (token == null) {
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, displayId="
-                    + mDisplayId);
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
+                    mDisplayId);
             newFocus = null;
         } else {
             newFocus = mService.mWindowManager.mRoot.getAppWindowToken(token);
@@ -1313,8 +1306,9 @@
                 Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
                         + ", displayId=" + mDisplayId);
             }
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Set focused app to: " + newFocus
-                    + " moveFocusNow=" + moveFocusNow + " displayId=" + mDisplayId);
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+                    "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
+                            moveFocusNow, mDisplayId);
         }
 
         final boolean changed = mDisplayContent.setFocusedApp(newFocus);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c54ccd4..c9e84ec 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -154,12 +154,11 @@
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.TaskPersister.DEBUG;
 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -239,6 +238,7 @@
 import com.android.server.am.AppTimeTracker;
 import com.android.server.am.EventLogTags;
 import com.android.server.am.PendingIntentRecord;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.uri.UriPermissionOwner;
 import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
 import com.android.server.wm.ActivityStack.ActivityState;
@@ -1183,11 +1183,10 @@
                     info.applicationInfo.targetSdkVersion,
                     info.screenOrientation, mRotationAnimationHint,
                     mLaunchTaskBehind, isAlwaysFocusable());
-            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) {
-                Slog.v(TAG, "addAppToken: "
-                        + mAppWindowToken + " task=" + container + " at "
-                        + Integer.MAX_VALUE);
-            }
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addAppToken: %s"
+                            + " task=%s at %d", mAppWindowToken, container,
+                    Integer.MAX_VALUE);
+
             container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */);
         }
 
@@ -1204,12 +1203,11 @@
             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
             IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
             boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
-        if (DEBUG_STARTING_WINDOW) {
-            Slog.v(TAG, "setAppStartingWindow: token=" + appToken
-                    + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
-                    + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
-                    + " allowTaskSnapshot=" + allowTaskSnapshot);
-        }
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "setAppStartingWindow: token=%s"
+                    + " pkg=%s transferFrom=%s newTask=%b taskSwitch=%b processRunning=%b"
+                    + " allowTaskSnapshot=%b", appToken, pkg, transferFrom, newTask, taskSwitch,
+                processRunning, allowTaskSnapshot);
+
         if (mAppWindowToken == null) {
             Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken);
             return false;
@@ -3215,7 +3213,7 @@
             // Window configuration changes only effect windows, so don't require a screen freeze.
             int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION);
             if (freezableConfigChanges == 0 && mAppWindowToken.okToDisplay()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken);
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", appToken);
                 return;
             }
 
@@ -3229,11 +3227,9 @@
             if (mAppWindowToken == null) {
                 return;
             }
-            if (DEBUG_ORIENTATION) {
-                Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden="
-                        + mAppWindowToken.isHidden() + " freezing="
-                        + mAppWindowToken.isFreezingScreen());
-            }
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Clear freezing of %s: hidden=%b freezing=%b", appToken,
+                                mAppWindowToken.isHidden(), mAppWindowToken.isFreezingScreen());
             mAppWindowToken.stopFreezingScreen(true, force);
         }
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 2ab3e01..ab1f258 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2106,7 +2106,11 @@
             boolean aboveTop = top != null;
             final boolean stackShouldBeVisible = shouldBeVisible(starting);
             boolean behindFullscreenActivity = !stackShouldBeVisible;
-            final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null;
+            // We should not resume activities that being launched behind because these
+            // activities are actually behind other fullscreen activities, but still required
+            // to be visible (such as performing Recents animation).
+            final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null
+                    && top != null && !top.mLaunchTaskBehind;
             for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                 final TaskRecord task = mTaskHistory.get(taskNdx);
                 final ArrayList<ActivityRecord> activities = task.mActivities;
@@ -2332,11 +2336,7 @@
                 r.setVisible(true);
             }
             if (r != starting) {
-                // We should not resume activities that being launched behind because these
-                // activities are actually behind other fullscreen activities, but still required
-                // to be visible (such as performing Recents animation).
-                mStackSupervisor.startSpecificActivityLocked(r, andResume && !r.mLaunchTaskBehind,
-                        true /* checkConfig */);
+                mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
                 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 919141c..6ee64f3 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -386,6 +386,8 @@
                     throw new IllegalArgumentException("File descriptors passed in Intent");
                 }
 
+                // Get the flag earlier because the intent may be modified in resolveActivity below.
+                final boolean componentSpecified = intent.getComponent() != null;
                 // Don't modify the client's object!
                 intent = new Intent(intent);
 
@@ -409,7 +411,6 @@
                         .setCaller(caller)
                         .setResolvedType(resolvedTypes[i])
                         .setActivityInfo(aInfo)
-                        .setResultTo(resultTo)
                         .setRequestCode(-1)
                         .setCallingPid(callingPid)
                         .setCallingUid(callingUid)
@@ -417,7 +418,7 @@
                         .setRealCallingPid(realCallingPid)
                         .setRealCallingUid(realCallingUid)
                         .setActivityOptions(checkedOptions)
-                        .setComponentSpecified(intent.getComponent() != null)
+                        .setComponentSpecified(componentSpecified)
 
                         // Top activity decides on animation being run, so we allow only for the
                         // top one as otherwise an activity below might consume it.
@@ -430,7 +431,8 @@
             // Lock the loop to ensure the activities launched in a sequence.
             synchronized (mService.mGlobalLock) {
                 for (int i = 0; i < starters.length; i++) {
-                    final int startResult = starters[i].setOutActivity(outActivity).execute();
+                    final int startResult = starters[i].setResultTo(resultTo)
+                            .setOutActivity(outActivity).execute();
                     if (startResult < START_SUCCESS) {
                         // Abort by error result and recycle unused starters.
                         for (int j = i + 1; j < starters.length; j++) {
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 9d08e10..cc69b5a 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -249,7 +249,8 @@
         if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
             return interceptSuspendedByAdminPackage();
         }
-        final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage, mUserId);
+        final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
+                suspendingPackage, mUserId);
         mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
                 suspendingPackage, dialogInfo, mUserId);
         mCallingPid = mRealCallingPid;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index dbf06a5..54bb5f7 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1743,7 +1743,12 @@
             return START_SUCCESS;
         }
 
-        if (!mMovedToFront && mDoResume) {
+        if (mMovedToFront) {
+            // We moved the task to front, use starting window to hide initial drawn delay.
+            targetTaskTop.showStartingWindow(null /* prev */, false /* newTask */,
+                    true /* taskSwitch */);
+        } else if (mDoResume) {
+            // Make sure the stack and its belonging display are moved to topmost.
             mTargetStack.moveToFront("intentActivityFound");
         }
         // We didn't do anything...  but it was needed (a.k.a., client don't use that intent!)
@@ -2349,11 +2354,6 @@
                 }
 
                 mOptions = null;
-
-                // We are moving a task to the front, use starting window to hide initial drawn
-                // delay.
-                intentActivity.showStartingWindow(null /* prev */, false /* newTask */,
-                        true /* taskSwitch */);
             }
         }
         // Need to update mTargetStack because if task was moved out of it, the original stack may
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 66d52cc..93c461f 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -70,8 +70,9 @@
 import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
 import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
 import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -131,6 +132,7 @@
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.animation.ClipRectLRAnimation;
 import com.android.server.wm.animation.ClipRectTBAnimation;
 import com.android.server.wm.animation.CurvedTranslateAnimation;
@@ -1630,70 +1632,61 @@
             a = loadAnimationRes(lp, enter
                     ? com.android.internal.R.anim.voice_activity_open_enter
                     : com.android.internal.R.anim.voice_activity_open_exit);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation voice:"
-                    + " anim=" + a + " transit=" + appTransitionToString(transit)
-                    + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
+                    appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_CLOSE
                 || transit == TRANSIT_TASK_CLOSE
                 || transit == TRANSIT_TASK_TO_BACK)) {
             a = loadAnimationRes(lp, enter
                     ? com.android.internal.R.anim.voice_activity_close_enter
                     : com.android.internal.R.anim.voice_activity_close_exit);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation voice:"
-                    + " anim=" + a + " transit=" + appTransitionToString(transit)
-                    + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
+                    appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
             a = createRelaunchAnimation(frame, insets);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                    + " anim=" + a + " nextAppTransition=" + mNextAppTransition
-                    + " transit=" + appTransitionToString(transit)
-                    + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", a,
+                    mNextAppTransition, appTransitionToString(transit),
+                    Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                     mNextAppTransitionEnter : mNextAppTransitionExit);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                    + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
-                    + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
-                    + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
+                            + "isEntrance=%b Callers=%s",
+                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
             a = loadAnimationRes(mNextAppTransitionPackage, mNextAppTransitionInPlace);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                    + " anim=" + a + " nextAppTransition=ANIM_CUSTOM_IN_PLACE"
-                    + " transit=" + appTransitionToString(transit)
-                    + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
+                            + "transit=%s Callers=%s",
+                    a, appTransitionToString(transit), Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
             a = createClipRevealAnimationLocked(transit, enter, frame, displayFrame);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                            + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
-                            + " transit=" + appTransitionToString(transit)
-                            + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
+                            + "transit=%s Callers=%s",
+                    a, appTransitionToString(transit), Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
             a = createScaleUpAnimationLocked(transit, enter, frame);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                    + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
-                    + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
-                    + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
+                            + "isEntrance=%s Callers=%s",
+                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
                     frame, transit, taskId);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                String animName = mNextAppTransitionScaleUp ?
-                        "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
-                Slog.v(TAG, "applyAnimation:"
-                        + " anim=" + a + " nextAppTransition=" + animName
-                        + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
-                        + " Callers=" + Debug.getCallers(3));
-            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+                            + "Callers=%s",
+                    a,  mNextAppTransitionScaleUp
+                            ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
+                    appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
                 mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
             mNextAppTransitionScaleUp =
@@ -1701,30 +1694,27 @@
             a = createAspectScaledThumbnailEnterExitAnimationLocked(
                     getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
                     insets, surfaceInsets, stableInsets, freeform, taskId);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                String animName = mNextAppTransitionScaleUp ?
-                        "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
-                Slog.v(TAG, "applyAnimation:"
-                        + " anim=" + a + " nextAppTransition=" + animName
-                        + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
-                        + " Callers=" + Debug.getCallers(3));
-            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+                            + "Callers=%s",
+                    a, mNextAppTransitionScaleUp
+                            ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
+                        : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
+                    appTransitionToString(transit), enter, Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
             a = loadAnimationRes("android",
                     com.android.internal.R.anim.task_open_enter_cross_profile_apps);
-            Slog.v(TAG,
-                    "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:"
-                            + " anim=" + a + " transit=" + appTransitionToString(transit)
-                            + " isEntrance=true" + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
+                            + "anim=%s transit=%s isEntrance=true Callers=%s",
+                    a, appTransitionToString(transit), Debug.getCallers(3));
         } else if (transit == TRANSIT_TASK_CHANGE_WINDOWING_MODE) {
             // In the absence of a specific adapter, we just want to keep everything stationary.
             a = new AlphaAnimation(1.f, 1.f);
             a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                Slog.v(TAG, "applyAnimation:"
-                        + " anim=" + a + " transit=" + appTransitionToString(transit)
-                        + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
-            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
+                    a, appTransitionToString(transit), enter, Debug.getCallers(3));
         } else {
             int animAttr = 0;
             switch (transit) {
@@ -1787,12 +1777,11 @@
                             : WindowAnimation_launchTaskBehindTargetAnimation;
             }
             a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
-                    "applyAnimation:"
-                    + " anim=" + a
-                    + " animAttr=0x" + Integer.toHexString(animAttr)
-                    + " transit=" + appTransitionToString(transit) + " isEntrance=" + enter
-                    + " Callers=" + Debug.getCallers(3));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
+                            + "Callers=%s",
+                    a, animAttr, appTransitionToString(transit), enter,
+                    Debug.getCallers(3));
         }
         return a;
     }
@@ -1941,8 +1930,8 @@
     }
 
     void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
-        if (DEBUG_APP_TRANSITIONS) Slog.i(TAG, "Override pending remote transitionSet="
-                + isTransitionSet() + " adapter=" + remoteAnimationAdapter);
+        ProtoLog.i(WM_DEBUG_APP_TRANSITIONS, "Override pending remote transitionSet=%b adapter=%s",
+                        isTransitionSet(), remoteAnimationAdapter);
         if (isTransitionSet()) {
             clear();
             mNextAppTransitionType = NEXT_TRANSIT_TYPE_REMOTE;
@@ -2214,12 +2203,11 @@
      */
     boolean prepareAppTransitionLocked(@TransitionType int transit, boolean alwaysKeepCurrent,
             @TransitionFlags int flags, boolean forceOverride) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Prepare app transition:"
-                + " transit=" + appTransitionToString(transit)
-                + " " + this
-                + " alwaysKeepCurrent=" + alwaysKeepCurrent
-                + " displayId=" + mDisplayContent.getDisplayId()
-                + " Callers=" + Debug.getCallers(5));
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "Prepare app transition: transit=%s %s alwaysKeepCurrent=%b displayId=%d "
+                        + "Callers=%s",
+                appTransitionToString(transit), this, alwaysKeepCurrent,
+                mDisplayContent.getDisplayId(), Debug.getCallers(5));
         final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
                 && transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
         if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
@@ -2305,15 +2293,14 @@
             }
             if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
                     || !dc.mChangingApps.isEmpty()) {
-                if (DEBUG_APP_TRANSITIONS) {
-                    Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT."
-                            + " displayId=" + dc.getDisplayId()
-                            + " isTransitionSet()="
-                            + dc.mAppTransition.isTransitionSet()
-                            + " mOpeningApps.size()=" + dc.mOpeningApps.size()
-                            + " mClosingApps.size()=" + dc.mClosingApps.size()
-                            + " mChangingApps.size()=" + dc.mChangingApps.size());
-                }
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                            "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b "
+                                    + "mOpeningApps.size()=%d mClosingApps.size()=%d "
+                                    + "mChangingApps.size()=%d",
+                            dc.getDisplayId(), dc.mAppTransition.isTransitionSet(),
+                            dc.mOpeningApps.size(), dc.mClosingApps.size(),
+                            dc.mChangingApps.size());
+
                 setTimeout();
                 mService.mWindowPlacerLocked.performSurfacePlacement();
             }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 6b2f9da..20a871b 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -48,7 +48,7 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -66,6 +66,7 @@
 import android.view.animation.Animation;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.util.function.Predicate;
 
@@ -104,7 +105,7 @@
         }
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
 
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
         final AppTransition appTransition = mDisplayContent.mAppTransition;
         int transit = appTransition.getAppTransition();
         if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
@@ -348,7 +349,7 @@
         final int appsCount = openingApps.size();
         for (int i = 0; i < appsCount; i++) {
             AppWindowToken wtoken = openingApps.valueAt(i);
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", wtoken);
 
             if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
                 // This token isn't going to be animating. Add it to the list of tokens to
@@ -383,7 +384,7 @@
         for (int i = 0; i < appsCount; i++) {
             AppWindowToken wtoken = closingApps.valueAt(i);
 
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", wtoken);
             // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
             //       animating?
             wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
@@ -410,7 +411,7 @@
         final int appsCount = apps.size();
         for (int i = 0; i < appsCount; i++) {
             AppWindowToken wtoken = apps.valueAt(i);
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wtoken);
             wtoken.cancelAnimationOnly();
             wtoken.applyAnimationLocked(null, transit, true, false);
             wtoken.updateReportedVisibilityLocked();
@@ -445,13 +446,12 @@
     }
 
     private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "Checking " + apps.size() + " opening apps (frozen="
-                        + mService.mDisplayFrozen + " timeout="
-                        + mDisplayContent.mAppTransition.isTimeout() + ")...");
-        final ScreenRotationAnimation screenRotationAnimation =
-                mService.mAnimator.getScreenRotationAnimationLocked(
-                        Display.DEFAULT_DISPLAY);
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
+                mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
+
+        final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent(
+                Display.DEFAULT_DISPLAY).getRotationAnimation();
 
         if (!mDisplayContent.mAppTransition.isTimeout()) {
             // Imagine the case where we are changing orientation due to an app transition, but a
@@ -463,20 +463,18 @@
             // app transition.
             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
                     mDisplayContent.getDisplayRotation().needsUpdate()) {
-                if (DEBUG_APP_TRANSITIONS) {
-                    Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
-                }
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                        "Delaying app transition for screen rotation animation to finish");
                 return false;
             }
             for (int i = 0; i < apps.size(); i++) {
                 AppWindowToken wtoken = apps.valueAt(i);
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                        "Check opening app=" + wtoken + ": allDrawn="
-                                + wtoken.allDrawn + " startingDisplayed="
-                                + wtoken.startingDisplayed + " startingMoved="
-                                + wtoken.startingMoved + " isRelaunching()="
-                                + wtoken.isRelaunching() + " startingWindow="
-                                + wtoken.startingWindow);
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                                "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+                                        + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
+                                wtoken, wtoken.allDrawn, wtoken.startingDisplayed,
+                                wtoken.startingMoved, wtoken.isRelaunching(),
+                                wtoken.startingWindow);
 
 
                 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
@@ -496,15 +494,13 @@
 
             // We also need to wait for the specs to be fetched, if needed.
             if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
                 return false;
             }
 
             if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
-                if (DEBUG_APP_TRANSITIONS) {
-                    Slog.v(TAG, "unknownApps is not empty: "
-                            + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
-                }
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
+                            mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
                 return false;
             }
 
@@ -549,22 +545,20 @@
                 true /* ignoreHidden */);
 
         boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "New wallpaper target=" + wallpaperTarget
-                        + ", oldWallpaper=" + oldWallpaper
-                        + ", openingApps=" + openingApps
-                        + ", closingApps=" + closingApps);
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                        "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
+                        wallpaperTarget, oldWallpaper, openingApps, closingApps);
 
         if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
             transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit: " + AppTransition.appTransitionToString(transit));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "New transit: %s", AppTransition.appTransitionToString(transit));
         }
         // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
         // relies on the fact that we always execute a Keyguard transition after preparing one.
         else if (!isKeyguardGoingAwayTransit(transit)) {
             if (closingAppHasWallpaper && openingAppHasWallpaper) {
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
                 switch (transit) {
                     case TRANSIT_ACTIVITY_OPEN:
                     case TRANSIT_TASK_OPEN:
@@ -577,16 +571,17 @@
                         transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
                         break;
                 }
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                        "New transit: " + AppTransition.appTransitionToString(transit));
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                        "New transit: %s", AppTransition.appTransitionToString(transit));
             } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
                     && !openingApps.contains(oldWallpaper.mAppToken)
                     && closingApps.contains(oldWallpaper.mAppToken)
                     && topClosingApp == oldWallpaper.mAppToken) {
                 // We are transitioning from an activity with a wallpaper to one without.
                 transit = TRANSIT_WALLPAPER_CLOSE;
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
-                        + AppTransition.appTransitionToString(transit));
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                        "New transit away from wallpaper: %s",
+                                AppTransition.appTransitionToString(transit));
             } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
                     && openingApps.contains(wallpaperTarget.mAppToken)
                     && topOpeningApp == wallpaperTarget.mAppToken
@@ -594,8 +589,8 @@
                 // We are transitioning from an activity without
                 // a wallpaper to now showing the wallpaper
                 transit = TRANSIT_WALLPAPER_OPEN;
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
-                        + AppTransition.appTransitionToString(transit));
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "New transit into wallpaper: %s",
+                        AppTransition.appTransitionToString(transit));
             }
         }
         return transit;
@@ -722,8 +717,7 @@
             final WindowState win = mDisplayContent.findFocusedWindow();
             if (win != null) {
                 final AppWindowToken wtoken = win.mAppToken;
-                if (DEBUG_APP_TRANSITIONS)
-                    Slog.v(TAG, "Now animating app in place " + wtoken);
+                ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now animating app in place %s", wtoken);
                 wtoken.cancelAnimation();
                 wtoken.applyAnimationLocked(null, transit, false, false);
                 wtoken.updateReportedVisibilityLocked();
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index b52ade4..2b05024 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -22,7 +22,7 @@
 import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT;
 import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR;
 import static com.android.server.wm.AppWindowThumbnailProto.WIDTH;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
@@ -31,7 +31,6 @@
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.os.Binder;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -39,6 +38,7 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.animation.Animation;
 
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.SurfaceAnimator.Animatable;
 
 import java.util.function.Supplier;
@@ -104,9 +104,7 @@
                         window != null ? window.mOwnerUid : Binder.getCallingUid())
                 .build();
 
-        if (SHOW_TRANSACTIONS) {
-            Slog.i(TAG, "  THUMBNAIL " + mSurfaceControl + ": CREATE");
-        }
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "  THUMBNAIL %s: CREATE", mSurfaceControl);
 
         // Transfer the thumbnail to the surface
         drawSurface.copyFrom(mSurfaceControl);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f647fe4..2668628 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -62,17 +62,16 @@
 import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
 import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
 import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
@@ -124,6 +123,7 @@
 import com.android.server.display.color.ColorDisplayService;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord;
 import com.android.server.wm.WindowManagerService.H;
 
@@ -388,8 +388,8 @@
         removeDeadWindows();
 
         if (startingWindow != null) {
-            if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
-                    + win.mToken + ": first real window is shown, no animation");
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s"
+                        + ": first real window is shown, no animation", win.mToken);
             // If this initial window is animating, stop it -- we will do an animation to reveal
             // it from behind the starting window, so there is no need for it to also be doing its
             // own stuff.
@@ -480,8 +480,9 @@
         if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
             return;
         }
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this
-                + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5));
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "setClientHidden: %s clientHidden=%b Callers=%s", this, hideClient,
+                        Debug.getCallers(5));
         mClientHidden = hideClient;
         sendAppVisibilityToClients();
     }
@@ -507,12 +508,10 @@
             return;
         }
 
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
-            Slog.v(TAG_WM, "setAppVisibility("
-                    + appToken + ", visible=" + visible + "): " + appTransition
-                    + " hidden=" + isHidden() + " hiddenRequested="
-                    + hiddenRequested + " Callers=" + Debug.getCallers(6));
-        }
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "setAppVisibility(%s, visible=%b): %s hidden=%b hiddenRequested=%b Callers=%s",
+                    appToken, visible, appTransition, isHidden(), hiddenRequested,
+                    Debug.getCallers(6));
 
         final DisplayContent displayContent = getDisplayContent();
         displayContent.mOpeningApps.remove(this);
@@ -548,17 +547,20 @@
                 if (isHidden()) {
                     waitingToShow = true;
 
-                    // Let's reset the draw state in order to prevent the starting window to be
-                    // immediately dismissed when the app still has the surface.
-                    forAllWindows(w -> {
-                        if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
-                            w.mWinAnimator.resetDrawState();
+                    // If the client isn't hidden, we don't need to reset the drawing state.
+                    if (isClientHidden()) {
+                        // Let's reset the draw state in order to prevent the starting window to be
+                        // immediately dismissed when the app still has the surface.
+                        forAllWindows(w -> {
+                            if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
+                                w.mWinAnimator.resetDrawState();
 
-                            // Force add to mResizingWindows, so that we are guaranteed to get
-                            // another reportDrawn callback.
-                            w.resetLastContentInsets();
-                        }
-                    },  true /* traverseTopToBottom */);
+                                // Force add to mResizingWindows, so that we are guaranteed to get
+                                // another reportDrawn callback.
+                                w.resetLastContentInsets();
+                            }
+                        }, true /* traverseTopToBottom */);
+                    }
                 }
             }
 
@@ -570,7 +572,7 @@
 
             requestUpdateWallpaperIfNeeded();
 
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this);
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this);
             mAppStopped = false;
 
             transferStartingWindowFromHiddenAboveTokenIfNeeded();
@@ -593,10 +595,10 @@
                 if (win != null) {
                     final AppWindowToken focusedToken = win.mAppToken;
                     if (focusedToken != null) {
-                        if (DEBUG_APP_TRANSITIONS) {
-                            Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
-                                    + " adding " + focusedToken + " to mOpeningApps");
-                        }
+                        ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
+                                    "TRANSIT_TASK_OPEN_BEHIND,  adding %s to mOpeningApps",
+                                    focusedToken);
+
                         // Force animation to be loaded.
                         displayContent.mOpeningApps.add(focusedToken);
                     }
@@ -635,8 +637,9 @@
             final AccessibilityController accessibilityController =
                     mWmService.mAccessibilityController;
             boolean changed = false;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
-                    "Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout);
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "Changing app %s hidden=%b performLayout=%b", this, isHidden(),
+                            performLayout);
 
             boolean runningAppAnimation = false;
 
@@ -678,10 +681,9 @@
                 forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
             }
 
-            if (DEBUG_APP_TRANSITIONS) {
-                Slog.v(TAG_WM, "commitVisibility: " + this
-                        + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
-            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                        "commitVisibility: %s: hidden=%b hiddenRequested=%b", this,
+                                isHidden(), hiddenRequested);
 
             if (changed) {
                 displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
@@ -884,7 +886,7 @@
         }
         mRemovingFromDisplay = true;
 
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this);
 
         boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
 
@@ -900,11 +902,12 @@
             delayed = true;
         }
 
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
-                + " animation=" + getAnimation() + " animating=" + isSelfAnimating());
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                "Removing app %s delayed=%b animation=%s animating=%b", this, delayed,
+                        getAnimation(), isSelfAnimating());
 
-        if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
-                + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s"
+                + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4));
 
         if (mStartingData != null) {
             removeStartingWindow();
@@ -920,8 +923,8 @@
         final TaskStack stack = getStack();
         if (delayed && !isEmpty()) {
             // set the token aside because it has an active animation to be finished
-            if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
-                    "removeAppToken make exiting: " + this);
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                    "removeAppToken make exiting: %s", this);
             if (stack != null) {
                 stack.mExitingAppTokens.add(this);
             }
@@ -941,8 +944,9 @@
 
         final DisplayContent dc = getDisplayContent();
         if (dc.mFocusedApp == this) {
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this
-                   + " displayId=" + dc.getDisplayId());
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+                    "Removing focused app token:%s displayId=%d", this,
+                            dc.getDisplayId());
             dc.setFocusedApp(null);
             mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
         }
@@ -1006,8 +1010,8 @@
      * up of the surfaces
      */
     void notifyAppResumed(boolean wasStopped) {
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
-                + " " + this);
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s",
+                wasStopped, this);
         mAppStopped = false;
         // Allow the window to turn the screen on once the app is resumed again.
         setCurrentLaunchCanTurnScreenOn(true);
@@ -1021,7 +1025,7 @@
      * keeping alive in case they were still being used.
      */
     void notifyAppStopped() {
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
         mAppStopped = true;
         // Reset the last saved PiP snap fraction on app stop.
         mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
@@ -1084,12 +1088,12 @@
     void postWindowRemoveStartingWindowCleanup(WindowState win) {
         // TODO: Something smells about the code below...Is there a better way?
         if (startingWindow == win) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Notify removed startingWindow %s", win);
             removeStartingWindow();
         } else if (mChildren.size() == 0) {
             // If this is the last window and we had requested a starting transition window,
             // well there is no point now.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData");
             mStartingData = null;
             if (mHiddenSetFromTransferredStartingWindow) {
                 // We set the hidden state to false for the token from a transferred starting window.
@@ -1100,8 +1104,7 @@
         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
             // If this is the last window except for a starting transition window,
             // we need to get rid of the starting transition.
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
-                    + win);
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Last window, removing starting window %s", win);
             removeStartingWindow();
         }
     }
@@ -1110,8 +1113,8 @@
         for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
             WindowState win = mChildren.get(winNdx);
             if (win.mAppDied) {
-                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
-                        "removeDeadWindows: " + win);
+                ProtoLog.w(WM_DEBUG_ADD_REMOVE,
+                        "removeDeadWindows: %s", win);
                 // Set mDestroying, we don't want any animation or delayed removal here.
                 win.mDestroying = true;
                 // Also removes child windows.
@@ -1132,8 +1135,8 @@
     }
 
     void setWillReplaceWindows(boolean animate) {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
-                "Marking app token " + this + " with replacing windows.");
+        ProtoLog.d(WM_DEBUG_ADD_REMOVE,
+                "Marking app token %s with replacing windows.", this);
 
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState w = mChildren.get(i);
@@ -1142,8 +1145,8 @@
     }
 
     void setWillReplaceChildWindows() {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
-                + " with replacing child windows.");
+        ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Marking app token %s"
+                + " with replacing child windows.", this);
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState w = mChildren.get(i);
             w.setWillReplaceChildWindows();
@@ -1151,8 +1154,8 @@
     }
 
     void clearWillReplaceWindows() {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
-                "Resetting app token " + this + " of replacing window marks.");
+        ProtoLog.d(WM_DEBUG_ADD_REMOVE,
+                "Resetting app token %s of replacing window marks.", this);
 
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final WindowState w = mChildren.get(i);
@@ -1317,10 +1320,9 @@
     }
 
     void reparent(Task task, int position) {
-        if (DEBUG_ADD_REMOVE) {
-            Slog.i(TAG_WM, "reparent: moving app token=" + this
-                    + " to task=" + task.mTaskId + " at " + position);
-        }
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving app token=%s"
+                    + " to task=%d at %d", this, task.mTaskId, position);
+
         if (task == null) {
             throw new IllegalArgumentException("reparent: could not find task");
         }
@@ -1336,8 +1338,8 @@
                         + " belongs to a different stack than " + task);
         }
 
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
-                + " from task=" + currentTask);
+        ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reParentWindowToken: removing window token=%s"
+                + " from task=%s"  , this, currentTask);
         final DisplayContent prevDisplayContent = getDisplayContent();
 
         mReparenting = true;
@@ -1457,9 +1459,10 @@
     }
 
     void startFreezingScreen() {
-        if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
-                + isHidden() + " freezing=" + mFreezingScreen + " hiddenRequested="
-                + hiddenRequested);
+        ProtoLog.i(WM_DEBUG_ORIENTATION,
+                "Set freezing of %s: hidden=%b freezing=%b hiddenRequested=%b. %s",
+                        appToken, isHidden(), mFreezingScreen, hiddenRequested,
+                new RuntimeException().fillInStackTrace());
         if (!hiddenRequested) {
             if (!mFreezingScreen) {
                 mFreezingScreen = true;
@@ -1483,7 +1486,8 @@
         if (!mFreezingScreen) {
             return;
         }
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "Clear freezing of %s force=%b", this, force);
         final int count = mChildren.size();
         boolean unfrozeWindows = false;
         for (int i = 0; i < count; i++) {
@@ -1491,7 +1495,7 @@
             unfrozeWindows |= w.onStopFreezingScreen();
         }
         if (force || unfrozeWindows) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this);
             mFreezingScreen = false;
             mWmService.unregisterAppFreezeListener(this);
             mWmService.mAppsFreezingScreen--;
@@ -1542,8 +1546,8 @@
             // letting windows get shown immediately without any more transitions.
             getDisplayContent().mSkipAppTransitionAnimation = true;
 
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
-                    + " from " + fromToken + " to " + this);
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s"
+                    + " from %s to %s", tStartingWindow, fromToken, this);
 
             final long origId = Binder.clearCallingIdentity();
             try {
@@ -1561,8 +1565,8 @@
                 tStartingWindow.mToken = this;
                 tStartingWindow.mAppToken = this;
 
-                if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                        "Removing starting " + tStartingWindow + " from " + fromToken);
+                ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                        "Removing starting %s from %s", tStartingWindow, fromToken);
                 fromToken.removeChild(tStartingWindow);
                 fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
                 fromToken.mHiddenSetFromTransferredStartingWindow = false;
@@ -1603,8 +1607,8 @@
         } else if (fromToken.mStartingData != null) {
             // The previous app was getting ready to show a
             // starting window, but hasn't yet done so.  Steal it!
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
-                    "Moving pending starting from " + fromToken + " to " + this);
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                    "Moving pending starting from %s to %s", fromToken, this);
             mStartingData = fromToken.mStartingData;
             fromToken.mStartingData = null;
             fromToken.startingMoved = true;
@@ -1876,9 +1880,10 @@
         if (mFreezingScreen) {
             showAllWindowsLocked();
             stopFreezingScreen(false, true);
-            if (DEBUG_ORIENTATION) Slog.i(TAG,
-                    "Setting mOrientationChangeComplete=true because wtoken " + this
-                    + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
+            ProtoLog.i(WM_DEBUG_ORIENTATION,
+                            "Setting mOrientationChangeComplete=true because wtoken %s "
+                                    + "numInteresting=%d numDrawn=%d",
+                            this, mNumInterestingWindows, mNumDrawnWindows);
             // This will set mOrientationChangeComplete and cause a pass through layout.
             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
                     "checkAppWindowsReadyToShow: freezingScreen");
@@ -1982,7 +1987,7 @@
         boolean isInterestingAndDrawn = false;
 
         if (!allDrawn && w.mightAffectAllDrawn()) {
-            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+            if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
                         + ", isAnimationSet=" + isSelfAnimating());
                 if (!w.isDrawnLw()) {
@@ -2003,10 +2008,12 @@
                     if (w.isDrawnLw()) {
                         mNumDrawnWindows++;
 
-                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
-                                + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
-                                + " freezingScreen=" + mFreezingScreen
-                                + " mAppFreezing=" + w.mAppFreezing);
+                        if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) {
+                            Slog.v(TAG, "tokenMayBeDrawn: "
+                                    + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
+                                    + " freezingScreen=" + mFreezingScreen
+                                    + " mAppFreezing=" + w.mAppFreezing);
+                        }
 
                         isInterestingAndDrawn = true;
                     }
@@ -2122,9 +2129,7 @@
         // If this is a translucent window, then don't show a starting window -- the current
         // effect (a full-screen opaque starting window that fades away to the real contents
         // when it is ready) does not work for this.
-        if (DEBUG_STARTING_WINDOW) {
-            Slog.v(TAG, "Checking theme of starting window: 0x" + Integer.toHexString(theme));
-        }
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme);
         if (theme != 0) {
             AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
                     com.android.internal.R.styleable.Window,
@@ -2142,11 +2147,8 @@
                     com.android.internal.R.styleable.Window_windowShowWallpaper, false);
             final boolean windowDisableStarting = ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowDisablePreview, false);
-            if (DEBUG_STARTING_WINDOW) {
-                Slog.v(TAG, "Translucent=" + windowIsTranslucent
-                        + " Floating=" + windowIsFloating
-                        + " ShowWallpaper=" + windowShowWallpaper);
-            }
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s",
+                        windowIsTranslucent, windowIsFloating, windowShowWallpaper);
             if (windowIsTranslucent) {
                 return false;
             }
@@ -2178,7 +2180,7 @@
             return false;
         }
 
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
         mStartingData = new SplashScreenStartingData(mWmService, pkg,
                 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
                 getMergedOverrideConfiguration());
@@ -2192,7 +2194,7 @@
             return false;
         }
 
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
         mStartingData = new SnapshotStartingData(mWmService, snapshot);
         scheduleAddStartingWindow();
         return true;
@@ -2203,7 +2205,7 @@
         // want to process the message ASAP, before any other queued
         // messages.
         if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING");
             mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
         }
     }
@@ -2220,18 +2222,17 @@
 
                 if (mStartingData == null) {
                     // Animation has been canceled... do nothing.
-                    if (DEBUG_STARTING_WINDOW) {
-                        Slog.v(TAG, "startingData was nulled out before handling"
-                                + " mAddStartingWindow: " + AppWindowToken.this);
-                    }
+                    ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                            "startingData was nulled out before handling"
+                                + " mAddStartingWindow: %s", AppWindowToken.this);
                     return;
                 }
                 startingData = mStartingData;
             }
 
-            if (DEBUG_STARTING_WINDOW) {
-                Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData);
-            }
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s",
+                    this, startingData);
+
 
             WindowManagerPolicy.StartingSurface surface = null;
             try {
@@ -2245,27 +2246,28 @@
                     // If the window was successfully added, then
                     // we need to remove it.
                     if (removed || mStartingData == null) {
-                        if (DEBUG_STARTING_WINDOW) {
-                            Slog.v(TAG, "Aborted starting " + AppWindowToken.this
-                                    + ": removed=" + removed + " startingData=" + mStartingData);
-                        }
+                        ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                                "Aborted starting %s: removed=%b startingData=%s",
+                                    AppWindowToken.this, removed, mStartingData);
+
                         startingWindow = null;
                         mStartingData = null;
                         abort = true;
                     } else {
                         startingSurface = surface;
                     }
-                    if (DEBUG_STARTING_WINDOW && !abort) {
-                        Slog.v(TAG,
-                                "Added starting " + AppWindowToken.this + ": startingWindow="
-                                        + startingWindow + " startingView=" + startingSurface);
+                    if (!abort) {
+                        ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                                "Added starting %s: startingWindow=%s startingView=%s",
+                                AppWindowToken.this, startingWindow, startingSurface);
                     }
                 }
                 if (abort) {
                     surface.remove();
                 }
-            } else if (DEBUG_STARTING_WINDOW) {
-                Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
+            } else {
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s",
+                        AppWindowToken.this);
             }
         }
     };
@@ -2308,9 +2310,7 @@
             if (mStartingData != null) {
                 // Starting window has not been added yet, but it is scheduled to be added.
                 // Go ahead and cancel the request.
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG_WM, "Clearing startingData for token=" + this);
-                }
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Clearing startingData for token=%s", this);
                 mStartingData = null;
             }
             return;
@@ -2324,31 +2324,28 @@
             startingWindow = null;
             startingDisplayed = false;
             if (surface == null) {
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                        "startingWindow was set but startingSurface==null, couldn't "
                             + "remove");
-                }
+
                 return;
             }
         } else {
-            if (DEBUG_STARTING_WINDOW) {
-                Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
-                        + this);
-            }
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                    "Tried to remove starting window but startingWindow was null: %s",
+                        this);
             return;
         }
 
-        if (DEBUG_STARTING_WINDOW) {
-            Slog.v(TAG_WM, "Schedule remove starting " + this
-                    + " startingWindow=" + startingWindow
-                    + " startingView=" + startingSurface
-                    + " Callers=" + Debug.getCallers(5));
-        }
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s"
+                    + " startingView=%s Callers=%s",
+                    this, startingWindow, startingSurface, Debug.getCallers(5));
+
 
         // Use the same thread to remove the window as we used to add it, as otherwise we end up
         // with things in the view hierarchy being called from different threads.
         mWmService.mAnimationHandler.post(() -> {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface);
             try {
                 surface.remove();
             } catch (Exception e) {
@@ -2544,7 +2541,7 @@
      * Creates a layer to apply crop to an animation.
      */
     private SurfaceControl createAnimationBoundsLayer(Transaction t) {
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.i(TAG, "Creating animation bounds layer");
+        ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer");
         final SurfaceControl.Builder builder = makeAnimationLeash()
                 .setParent(getAnimationLeashParent())
                 .setName(getSurfaceControl() + " - animation-bounds");
@@ -2580,10 +2577,9 @@
             boolean isVoiceInteraction) {
 
         if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
-            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."
-                        + " atoken=" + this);
-            }
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                    "applyAnimation: transition animation is disabled or skipped. "
+                            + "atoken=%s", this);
             cancelAnimation();
             return false;
         }
@@ -2683,8 +2679,8 @@
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         final int width = displayInfo.appWidth;
         final int height = displayInfo.appHeight;
-        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
-                "applyAnimation: atoken=" + this);
+        ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+                "applyAnimation: atoken=%s", this);
 
         // Determine the visible rect to calculate the thumbnail clip
         final WindowState win = findMainWindow();
@@ -2724,9 +2720,10 @@
             // screen gets the enter animation. Both appear in the mOpeningApps set.
             enter = false;
         }
-        if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
-                + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
-                + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
+        ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
+                "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
+                        + "surfaceInsets=%s",
+                AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
         final Configuration displayConfig = displayContent.getConfiguration();
         final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
                 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
@@ -2982,7 +2979,7 @@
         final GraphicBuffer thumbnailHeader =
                 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId);
         if (thumbnailHeader == null) {
-            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
+            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %d", taskId);
             return;
         }
         clearThumbnail();
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index 7557271a..b4cecff 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -16,16 +16,14 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 
-import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.util.Slog;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.io.PrintWriter;
 import java.util.function.Supplier;
 
@@ -33,14 +31,15 @@
  * Four black surfaces put together to make a black frame.
  */
 public class BlackFrame {
-    class BlackSurface {
+    static class BlackSurface {
         final int left;
         final int top;
         final int layer;
         final SurfaceControl surface;
 
         BlackSurface(SurfaceControl.Transaction transaction, int layer,
-                int l, int t, int r, int b, DisplayContent dc) throws OutOfResourcesException {
+                int l, int t, int r, int b, DisplayContent dc,
+                SurfaceControl surfaceControl) throws OutOfResourcesException {
             left = l;
             top = t;
             this.layer = layer;
@@ -50,7 +49,7 @@
             surface = dc.makeOverlay()
                     .setName("BlackSurface")
                     .setColorLayer()
-                    .setParent(null) // TODO: Work-around for b/69259549
+                    .setParent(surfaceControl)
                     .build();
             transaction.setWindowCrop(surface, w, h);
             transaction.setLayerStack(surface, dc.getDisplayId());
@@ -58,46 +57,15 @@
             transaction.setLayer(surface, layer);
             transaction.setPosition(surface, left, top);
             transaction.show(surface);
-            if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
-                            "  BLACK " + surface + ": CREATE layer=" + layer);
-        }
-
-        void setAlpha(SurfaceControl.Transaction t, float alpha) {
-            t.setAlpha(surface, alpha);
-        }
-
-        void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
-            mTmpMatrix.setTranslate(left, top);
-            mTmpMatrix.postConcat(matrix);
-            mTmpMatrix.getValues(mTmpFloats);
-            t.setPosition(surface, mTmpFloats[Matrix.MTRANS_X],
-                    mTmpFloats[Matrix.MTRANS_Y]);
-            t.setMatrix(surface,
-                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
-                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            if (false) {
-                Slog.i(TAG_WM, "Black Surface @ (" + left + "," + top + "): ("
-                        + mTmpFloats[Matrix.MTRANS_X] + ","
-                        + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
-                        + mTmpFloats[Matrix.MSCALE_X] + ","
-                        + mTmpFloats[Matrix.MSCALE_Y] + "]["
-                        + mTmpFloats[Matrix.MSKEW_X] + ","
-                        + mTmpFloats[Matrix.MSKEW_Y] + "]");
-            }
-        }
-
-        void clearMatrix(SurfaceControl.Transaction t) {
-            t.setMatrix(surface, 1, 0, 0, 1);
+            ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
+                    "  BLACK %s: CREATE layer=%d", surface, layer);
         }
     }
 
-    final Rect mOuterRect;
-    final Rect mInnerRect;
-    final Matrix mTmpMatrix = new Matrix();
-    final float[] mTmpFloats = new float[9];
-    final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
+    private final Rect mOuterRect;
+    private final Rect mInnerRect;
+    private final BlackSurface[] mBlackSurfaces = new BlackSurface[4];
 
-    final boolean mForceDefaultOrientation;
     private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
 
     public void printTo(String prefix, PrintWriter pw) {
@@ -114,12 +82,12 @@
     }
 
     public BlackFrame(Supplier<SurfaceControl.Transaction> factory, SurfaceControl.Transaction t,
-            Rect outer, Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation)
+            Rect outer, Rect inner, int layer, DisplayContent dc, boolean forceDefaultOrientation,
+            SurfaceControl surfaceControl)
             throws OutOfResourcesException {
         boolean success = false;
 
         mTransactionFactory = factory;
-        mForceDefaultOrientation = forceDefaultOrientation;
 
         // TODO: Why do we use 4 surfaces instead of just one big one behind the screenshot?
         // b/68253229
@@ -128,19 +96,20 @@
         try {
             if (outer.top < inner.top) {
                 mBlackSurfaces[0] = new BlackSurface(t, layer,
-                        outer.left, outer.top, inner.right, inner.top, dc);
+                        outer.left, outer.top, inner.right, inner.top, dc, surfaceControl);
             }
             if (outer.left < inner.left) {
                 mBlackSurfaces[1] = new BlackSurface(t, layer,
-                        outer.left, inner.top, inner.left, outer.bottom, dc);
+                        outer.left, inner.top, inner.left, outer.bottom, dc, surfaceControl);
             }
             if (outer.bottom > inner.bottom) {
                 mBlackSurfaces[2] = new BlackSurface(t, layer,
-                        inner.left, inner.bottom, outer.right, outer.bottom, dc);
+                        inner.left, inner.bottom, outer.right, outer.bottom, dc,
+                        surfaceControl);
             }
             if (outer.right > inner.right) {
                 mBlackSurfaces[3] = new BlackSurface(t, layer,
-                        inner.right, outer.top, outer.right, inner.bottom, dc);
+                        inner.right, outer.top, outer.right, inner.bottom, dc, surfaceControl);
             }
             success = true;
         } finally {
@@ -151,51 +120,14 @@
     }
 
     public void kill() {
-        if (mBlackSurfaces != null) {
-            SurfaceControl.Transaction t = mTransactionFactory.get();
-            for (int i=0; i<mBlackSurfaces.length; i++) {
-                if (mBlackSurfaces[i] != null) {
-                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
-                            "  BLACK " + mBlackSurfaces[i].surface + ": DESTROY");
-                    t.remove(mBlackSurfaces[i].surface);
-                    mBlackSurfaces[i] = null;
-                }
-            }
-            t.apply();
-        }
-    }
-
-    public void hide(SurfaceControl.Transaction t) {
-        if (mBlackSurfaces != null) {
-            for (int i=0; i<mBlackSurfaces.length; i++) {
-                if (mBlackSurfaces[i] != null) {
-                    t.hide(mBlackSurfaces[i].surface);
-                }
-            }
-        }
-    }
-
-    public void setAlpha(SurfaceControl.Transaction t, float alpha) {
-        for (int i=0; i<mBlackSurfaces.length; i++) {
+        SurfaceControl.Transaction t = mTransactionFactory.get();
+        for (int i = 0; i < mBlackSurfaces.length; i++) {
             if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].setAlpha(t, alpha);
+                ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "  BLACK %s: DESTROY", mBlackSurfaces[i].surface);
+                t.remove(mBlackSurfaces[i].surface);
+                mBlackSurfaces[i] = null;
             }
         }
-    }
-
-    public void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
-        for (int i=0; i<mBlackSurfaces.length; i++) {
-            if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].setMatrix(t, matrix);
-            }
-        }
-    }
-
-    public void clearMatrix(SurfaceControl.Transaction t) {
-        for (int i=0; i<mBlackSurfaces.length; i++) {
-            if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].clearMatrix(t);
-            }
-        }
+        t.apply();
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6462744..6d9a008 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -59,11 +59,10 @@
 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 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_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -100,24 +99,21 @@
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.DisplayContentProto.STACKS;
 import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.REPORT_FOCUS_CHANGE;
@@ -133,7 +129,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
-import static com.android.server.wm.WindowManagerService.logSurface;
 import static com.android.server.wm.WindowState.EXCLUSION_LEFT;
 import static com.android.server.wm.WindowState.EXCLUSION_RIGHT;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -173,6 +168,7 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayCutout;
@@ -202,6 +198,7 @@
 import com.android.internal.util.function.pooled.PooledLambda;
 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;
 import com.android.server.wm.utils.RotationCache;
 import com.android.server.wm.utils.WmDisplayCutout;
@@ -442,11 +439,6 @@
     /** A collection of windows that provide tap exclude regions inside of them. */
     final ArraySet<WindowState> mTapExcludeProvidingWindows = new ArraySet<>();
 
-    private boolean mHaveBootMsg = false;
-    private boolean mHaveApp = false;
-    private boolean mHaveWallpaper = false;
-    private boolean mHaveKeyguard = true;
-
     private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList();
 
     private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult =
@@ -497,6 +489,8 @@
     /** Windows removed since {@link #mCurrentFocus} was set to null. Used for ANR blaming. */
     final ArrayList<WindowState> mWinRemovedSinceNullFocus = new ArrayList<>();
 
+    private ScreenRotationAnimation mScreenRotationAnimation;
+
     /**
      * We organize all top-level Surfaces in to the following layers.
      * mOverlayLayer contains a few Surfaces which are always on top of others
@@ -521,9 +515,6 @@
      */
     private int mDeferUpdateImeTargetCount;
 
-    /** Temporary float array to retrieve 3x3 matrix values. */
-    private final float[] mTmpFloats = new float[9];
-
     private MagnificationSpec mMagnificationSpec;
 
     private InputMonitor mInputMonitor;
@@ -600,8 +591,8 @@
 
     private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
         final AppWindowToken focusedApp = mFocusedApp;
-        if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w
-                + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys());
+        ProtoLog.v(WM_DEBUG_FOCUS, "Looking for focus: %s, flags=%d, canReceive=%b",
+                w, w.mAttrs.flags, w.canReceiveKeys());
 
         if (!w.canReceiveKeys()) {
             return false;
@@ -611,22 +602,22 @@
 
         // If this window's application has been removed, just skip it.
         if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
-            if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
-                    + (wtoken.removed ? "removed" : "sendingToBottom"));
+            ProtoLog.v(WM_DEBUG_FOCUS, "Skipping %s because %s", wtoken,
+                    (wtoken.removed ? "removed" : "sendingToBottom"));
             return false;
         }
 
         if (focusedApp == null) {
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null"
-                    + " using new focus @ " + w);
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+                    "findFocusedWindow: focusedApp=null using new focus @ %s", w);
             mTmpWindow = w;
             return true;
         }
 
         if (!focusedApp.windowsAreFocusable()) {
             // Current focused app windows aren't focusable...
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not"
-                    + " focusable using new focus @ " + w);
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: focusedApp windows not"
+                    + " focusable using new focus @ %s", w);
             mTmpWindow = w;
             return true;
         }
@@ -636,14 +627,14 @@
         if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) {
             if (focusedApp.compareTo(wtoken) > 0) {
                 // App stack below focused app stack. No focus for you!!!
-                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
-                        "findFocusedWindow: Reached focused app=" + focusedApp);
+                ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
+                        "findFocusedWindow: Reached focused app=%s", focusedApp);
                 mTmpWindow = null;
                 return true;
             }
         }
 
-        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w);
+        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: Found new focus @ %s", w);
         mTmpWindow = w;
         return true;
     };
@@ -1146,7 +1137,8 @@
      */
     void initializeDisplayOverrideConfiguration() {
         if (mAcitvityDisplay != null) {
-            mAcitvityDisplay.onInitializeOverrideConfiguration(getRequestedOverrideConfiguration());
+            mAcitvityDisplay.getRequestedOverrideConfiguration()
+                    .updateFrom(getRequestedOverrideConfiguration());
         }
     }
 
@@ -1309,9 +1301,9 @@
     void applyRotationLocked(final int oldRotation, final int rotation) {
         mDisplayRotation.applyCurrentRotation(rotation);
         final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
-        final ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
-                ? null : mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
         final Transaction transaction = getPendingTransaction();
+        ScreenRotationAnimation screenRotationAnimation = rotateSeamlessly
+                ? null : getRotationAnimation();
         // We need to update our screen size information to match the new rotation. If the rotation
         // has actually changed then this method will return true and, according to the comment at
         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
@@ -1334,7 +1326,7 @@
 
         forAllWindows(w -> {
             if (w.mHasSurface && !rotateSeamlessly) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Set mOrientationChanging of %s", w);
                 w.setOrientationChanging(true);
                 mWmService.mRoot.mOrientationChangeComplete = false;
                 w.mLastFreezeDuration = 0;
@@ -1998,8 +1990,9 @@
 
         if (mWmService.mDisplayFrozen) {
             if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
-                        + " is frozen, return " + mLastWindowForcedOrientation);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Display id=%d is frozen, return %d", mDisplayId,
+                                mLastWindowForcedOrientation);
                 // If the display is frozen, some activities may be in the middle of restarting, and
                 // thus have removed their old window. If the window has the flag to hide the lock
                 // screen, then the lock screen can re-appear and inflict its own orientation on us.
@@ -2011,8 +2004,9 @@
                 // window. We don't want to check the show when locked window directly though as
                 // things aren't stable while the display is frozen, for example the window could be
                 // momentarily unavailable due to activity relaunch.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
-                        + " is frozen while keyguard locked, return " + getLastOrientation());
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Display id=%d is frozen while keyguard locked, return %d",
+                                mDisplayId, getLastOrientation());
                 return getLastOrientation();
             }
         } else {
@@ -2393,6 +2387,7 @@
             super.removeImmediately();
             if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
             mPointerEventDispatcher.dispose();
+            setRotationAnimation(null);
             mWmService.mAnimator.removeDisplayLocked(mDisplayId);
             mWindowingLayer.release();
             mOverlayLayer.release();
@@ -2557,6 +2552,17 @@
         return delta;
     }
 
+    public void setRotationAnimation(ScreenRotationAnimation screenRotationAnimation) {
+        if (mScreenRotationAnimation != null) {
+            mScreenRotationAnimation.kill();
+        }
+        mScreenRotationAnimation = screenRotationAnimation;
+    }
+
+    public ScreenRotationAnimation getRotationAnimation() {
+        return mScreenRotationAnimation;
+    }
+
     private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
             Matrix outMatrix) {
         // For rotations without Z-ordering we don't need the target rectangle's position.
@@ -2619,8 +2625,7 @@
         proto.write(DPI, mBaseDisplayDensity);
         mDisplayInfo.writeToProto(proto, DISPLAY_INFO);
         proto.write(ROTATION, getRotation());
-        final ScreenRotationAnimation screenRotationAnimation =
-                mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
+        final ScreenRotationAnimation screenRotationAnimation = getRotationAnimation();
         if (screenRotationAnimation != null) {
             screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
         }
@@ -2732,6 +2737,16 @@
             }
         }
 
+        final ScreenRotationAnimation rotationAnimation = getRotationAnimation();
+        if (rotationAnimation != null) {
+            pw.print(subPrefix);
+            pw.println("  mScreenRotationAnimation:");
+            rotationAnimation.printTo("  ", pw);
+        } else if (dumpAll) {
+            pw.print(subPrefix);
+            pw.println("  no ScreenRotationAnimation ");
+        }
+
         pw.println();
 
         // Dump stack references
@@ -2851,7 +2866,7 @@
         forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
 
         if (mTmpWindow == null) {
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "findFocusedWindow: No focusable windows.");
             return null;
         }
         return mTmpWindow;
@@ -2897,11 +2912,8 @@
             mWmService.mH.obtainMessage(REPORT_FOCUS_CHANGE, this).sendToTarget();
         }
 
-        if (DEBUG_FOCUS_LIGHT || DEBUG) {
-            Slog.v(TAG_WM, "Changing focus from "
-                    + mCurrentFocus + " to " + newFocus + " displayId=" + getDisplayId()
-                    + " Callers=" + Debug.getCallers(4));
-        }
+        ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Changing focus from %s to %s displayId=%d Callers=%s",
+                    mCurrentFocus, newFocus, getDisplayId(), Debug.getCallers(4));
         final WindowState oldFocus = mCurrentFocus;
         mCurrentFocus = newFocus;
         mLosingFocus.remove(newFocus);
@@ -3038,7 +3050,7 @@
                 Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
                         + w + " surface=" + wsa.mSurfaceController
                         + " token=" + w.mAppToken);
-                if (SHOW_TRANSACTIONS) logSurface(w, "LEAK DESTROY", false);
+                ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE LEAK DESTROY: %s", w);
                 wsa.destroySurface();
                 mTmpWindow = w;
             }
@@ -3333,34 +3345,38 @@
         }, true /* traverseTopToBottom */);
     }
 
-    boolean checkWaitingForWindows() {
+    /** @return {@code true} if there is window to wait before enabling the screen. */
+    boolean shouldWaitForSystemDecorWindowsOnBoot() {
+        if (!isDefaultDisplay && !supportsSystemDecorations()) {
+            // Nothing to wait because the secondary display doesn't support system decorations,
+            // there is no wallpaper, keyguard (status bar) or application (home) window to show
+            // during booting.
+            return false;
+        }
 
-        mHaveBootMsg = false;
-        mHaveApp = false;
-        mHaveWallpaper = false;
-        mHaveKeyguard = true;
+        final SparseBooleanArray drawnWindowTypes = new SparseBooleanArray();
+        // Presuppose keyguard is drawn because if its window isn't attached, we don't know if it
+        // wants to be shown or hidden, then it should not delay enabling the screen.
+        drawnWindowTypes.put(TYPE_STATUS_BAR, true);
 
-        final WindowState visibleWindow = getWindow(w -> {
-            if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+        final WindowState visibleNotDrawnWindow = getWindow(w -> {
+            if (w.mViewVisibility == View.VISIBLE && !w.mObscured && !w.isDrawnLw()) {
                 return true;
             }
             if (w.isDrawnLw()) {
-                if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
-                    mHaveBootMsg = true;
-                } else if (w.mAttrs.type == TYPE_APPLICATION
-                        || w.mAttrs.type == TYPE_DRAWN_APPLICATION) {
-                    mHaveApp = true;
-                } else if (w.mAttrs.type == TYPE_WALLPAPER) {
-                    mHaveWallpaper = true;
-                } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
-                    mHaveKeyguard = mWmService.mPolicy.isKeyguardDrawnLw();
+                final int type = w.mAttrs.type;
+                if (type == TYPE_BOOT_PROGRESS || type == TYPE_BASE_APPLICATION
+                        || type == TYPE_WALLPAPER) {
+                    drawnWindowTypes.put(type, true);
+                } else if (type == TYPE_STATUS_BAR) {
+                    drawnWindowTypes.put(TYPE_STATUS_BAR, mWmService.mPolicy.isKeyguardDrawnLw());
                 }
             }
             return false;
         });
 
-        if (visibleWindow != null) {
-            // We have a visible window.
+        if (visibleNotDrawnWindow != null) {
+            // Wait for the visible window to be drawn.
             return true;
         }
 
@@ -3372,23 +3388,27 @@
                         com.android.internal.R.bool.config_checkWallpaperAtBoot)
                 && !mWmService.mOnlyCore;
 
-        if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM,
-                "******** booted=" + mWmService.mSystemBooted
-                + " msg=" + mWmService.mShowingBootMessages
-                + " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp
-                + " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled
-                + " haveKeyguard=" + mHaveKeyguard);
+        final boolean haveBootMsg = drawnWindowTypes.get(TYPE_BOOT_PROGRESS);
+        final boolean haveApp = drawnWindowTypes.get(TYPE_BASE_APPLICATION);
+        final boolean haveWallpaper = drawnWindowTypes.get(TYPE_WALLPAPER);
+        final boolean haveKeyguard = drawnWindowTypes.get(TYPE_STATUS_BAR);
+
+        ProtoLog.i(WM_DEBUG_SCREEN_ON,
+                "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b "
+                        + "wallEnabled=%b haveKeyguard=%b",
+                mWmService.mSystemBooted, mWmService.mShowingBootMessages, haveBootMsg,
+                haveApp, haveWallpaper, wallpaperEnabled, haveKeyguard);
 
         // If we are turning on the screen to show the boot message, don't do it until the boot
         // message is actually displayed.
-        if (!mWmService.mSystemBooted && !mHaveBootMsg) {
+        if (!mWmService.mSystemBooted && !haveBootMsg) {
             return true;
         }
 
         // If we are turning on the screen after the boot is completed normally, don't do so until
         // we have the application and wallpaper.
         if (mWmService.mSystemBooted
-                && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) {
+                && ((!haveApp && !haveKeyguard) || (wallpaperEnabled && !haveWallpaper))) {
             return true;
         }
 
@@ -3741,7 +3761,7 @@
         convertCropForSurfaceFlinger(frame, rot, dw, dh);
 
         final ScreenRotationAnimation screenRotationAnimation =
-                mWmService.mAnimator.getScreenRotationAnimationLocked(DEFAULT_DISPLAY);
+                mWmService.mRoot.getDisplayContent(DEFAULT_DISPLAY).getRotationAnimation();
         final boolean inRotation = screenRotationAnimation != null &&
                 screenRotationAnimation.isAnimating();
         if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM, "Taking screenshot while rotating");
@@ -4214,8 +4234,8 @@
                         // associated with it will be removed as soon as their animations are
                         // complete.
                         cancelAnimation();
-                        if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                                "performLayout: App token exiting now removed" + token);
+                        ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                                "performLayout: App token exiting now removed %s", token);
                         token.removeIfPossible();
                     }
                 }
@@ -4245,15 +4265,15 @@
             final int orientation = super.getOrientation();
             if (orientation != SCREEN_ORIENTATION_UNSET
                     && orientation != SCREEN_ORIENTATION_BEHIND) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "App is requesting an orientation, return " + orientation
-                                + " for display id=" + mDisplayId);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                                "App is requesting an orientation, return %d for display id=%d",
+                                orientation, mDisplayId);
                 return orientation;
             }
 
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                    "No app is requesting an orientation, return " + getLastOrientation()
-                            + " for display id=" + mDisplayId);
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                            "No app is requesting an orientation, return %d for display id=%d",
+                            getLastOrientation(), mDisplayId);
             // The next app has not been requested to be visible, so we keep the current orientation
             // to prevent freezing/unfreezing the display too early.
             return getLastOrientation();
@@ -4490,8 +4510,9 @@
                         return SCREEN_ORIENTATION_UNSET;
                     }
                 }
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req
-                        + " for display id=" + mDisplayId);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "%s forcing orientation to %d for display id=%d", win, req,
+                                mDisplayId);
                 return (mLastWindowForcedOrientation = req);
             }
 
@@ -4666,20 +4687,7 @@
     void prepareSurfaces() {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "prepareSurfaces");
         try {
-            final ScreenRotationAnimation screenRotationAnimation =
-                    mWmService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
             final Transaction transaction = getPendingTransaction();
-            if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-                screenRotationAnimation.getEnterTransformation().getMatrix().getValues(mTmpFloats);
-                transaction.setMatrix(mWindowingLayer,
-                        mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
-                        mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-                transaction.setPosition(mWindowingLayer,
-                        mTmpFloats[Matrix.MTRANS_X], mTmpFloats[Matrix.MTRANS_Y]);
-                transaction.setAlpha(mWindowingLayer,
-                        screenRotationAnimation.getEnterTransformation().getAlpha());
-            }
-
             super.prepareSurfaces();
 
             // TODO: Once we totally eliminate global transaction we will pass transaction in here
@@ -4759,10 +4767,9 @@
 
     void executeAppTransition() {
         if (mAppTransition.isTransitionSet()) {
-            if (DEBUG_APP_TRANSITIONS) {
-                Slog.w(TAG_WM, "Execute app transition: " + mAppTransition + ", displayId: "
-                        + mDisplayId + " Callers=" + Debug.getCallers(5));
-            }
+            ProtoLog.w(WM_DEBUG_APP_TRANSITIONS,
+                    "Execute app transition: %s, displayId: %d Callers=%s",
+                        mAppTransition, mDisplayId, Debug.getCallers(5));
             mAppTransition.setReady();
             mWmService.mWindowPlacerLocked.requestTraversal();
         }
@@ -4909,6 +4916,10 @@
         return mWindowingLayer;
     }
 
+    SurfaceControl getOverlayLayer() {
+        return mOverlayLayer;
+    }
+
     /**
      * Updates the display's system gesture exclusion.
      *
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 10d48c4..7be4dbd 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -98,9 +98,9 @@
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
 import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -168,6 +168,7 @@
 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
 import com.android.server.policy.WindowOrientationListener;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wallpaper.WallpaperManagerInternal;
 import com.android.server.wm.utils.InsetUtils;
@@ -765,19 +766,19 @@
     /** Return false if it is not ready to turn on. */
     public boolean finishScreenTurningOn() {
         synchronized (mLock) {
-            if (DEBUG_SCREEN_ON) Slog.d(TAG,
-                    "finishScreenTurningOn: mAwake=" + mAwake
-                            + ", mScreenOnEarly=" + mScreenOnEarly
-                            + ", mScreenOnFully=" + mScreenOnFully
-                            + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
-                            + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
+            ProtoLog.d(WM_DEBUG_SCREEN_ON,
+                            "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
+                                    + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
+                                    + "mWindowManagerDrawComplete=%b",
+                            mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
+                            mWindowManagerDrawComplete);
 
             if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
                     || (mAwake && !mKeyguardDrawComplete)) {
                 return false;
             }
 
-            if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
+            ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
             mScreenOnListener = null;
             mScreenOnFully = true;
         }
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 4d188f4..414e496 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -23,8 +23,8 @@
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
 
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
@@ -58,6 +58,7 @@
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.policy.WindowOrientationListener;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.statusbar.StatusBarManagerInternal;
 
 import java.io.PrintWriter;
@@ -399,24 +400,24 @@
             if (mDeferredRotationPauseCount > 0) {
                 // Rotation updates have been paused temporarily. Defer the update until updates
                 // have been resumed.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, rotation is paused.");
                 return false;
             }
 
             final ScreenRotationAnimation screenRotationAnimation =
-                    mService.mAnimator.getScreenRotationAnimationLocked(displayId);
+                    mDisplayContent.getRotationAnimation();
             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
                 // Rotation updates cannot be performed while the previous rotation change animation
                 // is still in progress. Skip this update. We will try updating again after the
                 // animation is finished and the display is unfrozen.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, animation in progress.");
                 return false;
             }
             if (mService.mDisplayFrozen) {
                 // Even if the screen rotation animation has finished (e.g. isAnimating returns
                 // false), there is still some time where we haven't yet unfrozen the display. We
                 // also need to abort rotation here.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
                         "Deferring rotation, still finishing previous rotation");
                 return false;
             }
@@ -424,30 +425,30 @@
 
         if (!mService.mDisplayEnabled) {
             // No point choosing a rotation if the display is not enabled.
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "Deferring rotation, display is not enabled.");
             return false;
         }
 
         final int oldRotation = mRotation;
         final int lastOrientation = mLastOrientation;
         final int rotation = rotationForOrientation(lastOrientation, oldRotation);
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
-                + displayId + " based on lastOrientation=" + lastOrientation
-                + " and oldRotation=" + oldRotation);
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "Computed rotation=%d for display id=%d based on lastOrientation=%d and "
+                        + "oldRotation=%d",
+                rotation, displayId, lastOrientation, oldRotation);
 
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId
-                + " selected orientation " + lastOrientation
-                + ", got rotation " + rotation);
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "Display id=%d selected orientation %d, got rotation %d", displayId,
+                        lastOrientation, rotation);
 
         if (oldRotation == rotation) {
             // No change.
             return false;
         }
 
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + displayId
-                + " rotation changed to " + rotation
-                + " from " + oldRotation
-                + ", lastOrientation=" + lastOrientation);
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
+                        displayId, rotation, oldRotation, lastOrientation);
 
         if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
             mDisplayContent.mWaitingForConfig = true;
@@ -551,9 +552,8 @@
             mSeamlessRotationCount--;
         }
         if (mSeamlessRotationCount == 0) {
-            if (DEBUG_ORIENTATION) {
-                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
-            }
+            ProtoLog.i(WM_DEBUG_ORIENTATION,
+                    "Performing post-rotate rotation after seamless rotation");
             // Finish seamless rotation.
             mRotatingSeamlessly = false;
 
@@ -844,11 +844,12 @@
 
         // Could have been invoked due to screen turning on or off or
         // change of the currently visible window's orientation.
-        if (DEBUG_ORIENTATION) Slog.v(TAG, "screenOnEarly=" + screenOnEarly
-                + ", awake=" + awake + ", currentAppOrientation=" + mCurrentAppOrientation
-                + ", orientationSensorEnabled=" + mOrientationListener.mEnabled
-                + ", keyguardDrawComplete=" + keyguardDrawComplete
-                + ", windowManagerDrawComplete=" + windowManagerDrawComplete);
+        ProtoLog.v(WM_DEBUG_ORIENTATION,
+                "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, "
+                        + "orientationSensorEnabled=%b, keyguardDrawComplete=%b, "
+                        + "windowManagerDrawComplete=%b",
+                screenOnEarly, awake, mCurrentAppOrientation, mOrientationListener.mEnabled,
+                keyguardDrawComplete, windowManagerDrawComplete);
 
         boolean disable = true;
         // Note: We postpone the rotating of the screen until the keyguard as well as the
@@ -952,14 +953,11 @@
      */
     @VisibleForTesting
     int rotationForOrientation(int orientation, int lastRotation) {
-        if (DEBUG_ORIENTATION) {
-            Slog.v(TAG, "rotationForOrientation(orient="
-                        + orientation + ", last=" + lastRotation
-                        + "); user=" + mUserRotation + " "
-                        + (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
-                            ? "USER_ROTATION_LOCKED" : "")
+        ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s",
+                    orientation, lastRotation, mUserRotation,
+                    mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
+                            ? "USER_ROTATION_LOCKED" : ""
                         );
-        }
 
         if (isFixedToUserRotation()) {
             return mUserRotation;
@@ -1059,11 +1057,19 @@
                 preferredRotation = lastRotation;
             }
         } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED
-                && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
-            // Apply rotation lock.  Does not apply to NOSENSOR.
+                && orientation != ActivityInfo.SCREEN_ORIENTATION_NOSENSOR
+                && orientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+                && orientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+                && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
+                && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
+            // Apply rotation lock. Does not apply to NOSENSOR or specific rotations.
             // The idea is that the user rotation expresses a weak preference for the direction
             // of gravity and as NOSENSOR is never affected by gravity, then neither should
             // NOSENSOR be affected by rotation lock (although it will be affected by docks).
+            // Also avoid setting user rotation when app has preference over one particular rotation
+            // to avoid leaving the rotation to the reverse of it which has the compatible
+            // orientation, but isn't what app wants, when the user rotation is the reverse of the
+            // preferred rotation.
             preferredRotation = mUserRotation;
         } else {
             // No overriding preference.
@@ -1372,7 +1378,7 @@
 
         @Override
         public void onProposedRotationChanged(int rotation) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);
             Runnable r = mRunnableCache.get(rotation, null);
             if (r == null) {
                 r = new UpdateRunnable(rotation);
@@ -1385,14 +1391,14 @@
         public void enable(boolean clearCurrentRotation) {
             super.enable(clearCurrentRotation);
             mEnabled = true;
-            if (DEBUG_ORIENTATION) Slog.v(TAG, "Enabling listeners");
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners");
         }
 
         @Override
         public void disable() {
             super.disable();
             mEnabled = false;
-            if (DEBUG_ORIENTATION) Slog.v(TAG, "Disabling listeners");
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners");
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index f8f6334..d5f403f 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -113,7 +113,7 @@
 
                     final WindowState callingWin = mService.windowForClientLocked(
                             null, window, false);
-                    if (callingWin == null) {
+                    if (callingWin == null || callingWin.cantReceiveTouchInput()) {
                         Slog.w(TAG_WM, "Bad requesting window " + window);
                         return null;  // !!! TODO: throw here?
                     }
@@ -167,8 +167,7 @@
                     final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
                     if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
 
-                    final SurfaceControl.Transaction transaction =
-                            callingWin.getPendingTransaction();
+                    final SurfaceControl.Transaction transaction = mDragState.mTransaction;
                     transaction.setAlpha(surfaceControl, mDragState.mOriginalAlpha);
                     transaction.setPosition(
                             surfaceControl, touchX - thumbCenterX, touchY - thumbCenterY);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 17daabf..34820ac 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -19,10 +19,10 @@
 import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
 import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
 import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.animation.Animator;
@@ -58,6 +58,7 @@
 
 import com.android.internal.view.IDragAndDropPermissions;
 import com.android.server.LocalServices;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.util.ArrayList;
 
@@ -120,7 +121,7 @@
     // A surface used to catch input events for the drag-and-drop operation.
     SurfaceControl mInputSurface;
 
-    private final SurfaceControl.Transaction mTransaction;
+    final SurfaceControl.Transaction mTransaction;
 
     private final Rect mTmpClipRect = new Rect();
 
@@ -129,7 +130,6 @@
      * {@code true} when {@link #closeLocked()} is called.
      */
     private boolean mIsClosing;
-    IBinder mTransferTouchFromToken;
 
     DragState(WindowManagerService service, DragDropController controller, IBinder token,
             SurfaceControl surface, int flags, IBinder localWin) {
@@ -167,12 +167,11 @@
 
         mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
         mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
-        mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token);
-        mTransferTouchFromToken = null;
 
-        // syncInputWindows here to ensure the input channel isn't removed before the transfer.
+        // syncInputWindows here to ensure the input window info is sent before the
+        // transferTouchFocus is called.
         mTransaction.syncInputWindows();
-        mTransaction.apply();
+        mTransaction.apply(true);
     }
 
     /**
@@ -302,9 +301,7 @@
             mDragWindowHandle.frameBottom = mDisplaySize.y;
 
             // Pause rotations before a drag.
-            if (DEBUG_ORIENTATION) {
-                Slog.d(TAG_WM, "Pausing rotation during drag");
-            }
+            ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during drag");
             mDisplayContent.getDisplayRotation().pause();
         }
 
@@ -321,9 +318,7 @@
             mDragApplicationHandle = null;
 
             // Resume rotations after a drag.
-            if (DEBUG_ORIENTATION) {
-                Slog.d(TAG_WM, "Resuming rotation after drag");
-            }
+            ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after drag");
             mDisplayContent.getDisplayRotation().resume();
         }
     }
@@ -501,10 +496,9 @@
             Slog.i(TAG_WM, ">>> OPEN TRANSACTION notifyMoveLocked");
         }
         mTransaction.setPosition(mSurfaceControl, x - mThumbOffsetX, y - mThumbOffsetY).apply();
-        if (SHOW_TRANSACTIONS) {
-            Slog.i(TAG_WM, "  DRAG " + mSurfaceControl + ": pos=(" + (int) (x - mThumbOffsetX) + ","
-                    + (int) (y - mThumbOffsetY) + ")");
-        }
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "DRAG %s: pos=(%d,%d)", mSurfaceControl,
+                (int) (x - mThumbOffsetX), (int) (y - mThumbOffsetY));
+
         notifyLocationLocked(x, y);
     }
 
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 8e0531c..932b4fa 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -26,7 +26,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -49,6 +49,7 @@
 
 import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 import java.util.Set;
@@ -331,9 +332,7 @@
      * Layer assignment is assumed to be complete by the time this is called.
      */
     public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
-        if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) {
-            Slog.d(TAG_WM, "Input focus has changed to " + newWindow);
-        }
+        ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s", newWindow);
 
         if (newWindow != mInputFocus) {
             if (newWindow != null && newWindow.canReceiveKeys()) {
diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java
index 3db6dcf..b7184a5 100644
--- a/services/core/java/com/android/server/wm/InsetsControlTarget.java
+++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java
@@ -16,9 +16,21 @@
 
 package com.android.server.wm;
 
+import android.inputmethodservice.InputMethodService;
+import android.view.WindowInsets.Type.InsetType;
+
 /**
  * Generalization of an object that can control insets state.
  */
 interface InsetsControlTarget {
     void notifyInsetsControlChanged();
+
+    /**
+     * Instructs the control target to show inset sources.
+     *
+     * @param types to specify which types of insets source window should be shown.
+     * @param fromIme {@code true} if IME show request originated from {@link InputMethodService}.
+     */
+    default void showInsets(@InsetType int types, boolean fromIme) {
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ProtoLogGroup.java b/services/core/java/com/android/server/wm/ProtoLogGroup.java
index 313cceb..2e0ef14 100644
--- a/services/core/java/com/android/server/wm/ProtoLogGroup.java
+++ b/services/core/java/com/android/server/wm/ProtoLogGroup.java
@@ -27,8 +27,38 @@
  * must be included in services.core.wm.protologgroups build target.
  */
 public enum ProtoLogGroup implements IProtoLogGroup {
-    GENERIC_WM(true, true, false, "WindowManager"),
-
+    WM_ERROR(true, true, true, Consts.TAG_WM),
+    WM_DEBUG_ORIENTATION(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+            Consts.TAG_WM),
+    WM_DEBUG_FOCUS_LIGHT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_BOOT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_RESIZE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_ADD_REMOVE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_FOCUS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+    WM_DEBUG_STARTING_WINDOW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_SHOW_TRANSACTIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_SHOW_SURFACE_ALLOC(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_APP_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_APP_TRANSITIONS_ANIM(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_RECENTS_ANIMATIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_DRAW(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+    WM_DEBUG_REMOTE_ANIMATIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_SCREEN_ON(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM),
+    WM_DEBUG_KEEP_SCREEN_ON(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
+    WM_DEBUG_WINDOW_MOVEMENT(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+            Consts.TAG_WM),
     TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
 
     private final boolean mEnabled;
@@ -95,4 +125,11 @@
                 "Test completed successfully: %b %d %o %x %e %g %f %% %s.",
                 true, 1, 2, 3, 0.4, 0.5, 0.6, "ok");
     }
+
+    private static class Consts {
+        private static final String TAG_WM = "WindowManager";
+
+        private static final boolean ENABLE_DEBUG = true;
+        private static final boolean ENABLE_LOG_TO_PROTO_DEBUG = true;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 5cabbd9..31f4584 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -28,10 +28,10 @@
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.BoundsAnimationController.BOUNDS;
 import static com.android.server.wm.BoundsAnimationController.FADE_IN;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 
 import android.annotation.Nullable;
 import android.app.ActivityOptions;
@@ -42,6 +42,7 @@
 import android.util.Slog;
 import android.view.IRecentsAnimationRunner;
 
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
 
 /**
@@ -51,7 +52,6 @@
 class RecentsAnimation implements RecentsAnimationCallbacks,
         ActivityDisplay.OnStackOrderChangedListener {
     private static final String TAG = RecentsAnimation.class.getSimpleName();
-    private static final boolean DEBUG = DEBUG_RECENTS_ANIMATIONS;
 
     private final ActivityTaskManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
@@ -101,7 +101,8 @@
      * is updated to the current one.
      */
     void preloadRecentsActivity() {
-        if (DEBUG) Slog.d(TAG, "Preload recents with " + mTargetIntent);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s",
+                mTargetIntent);
         ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                 mTargetActivityType);
         ActivityRecord targetActivity = getTargetActivity(targetStack);
@@ -116,7 +117,8 @@
                 // keeps the original stopped state.
                 targetActivity.ensureActivityConfiguration(0 /* globalChanges */,
                         false /* preserveWindow */, true /* ignoreVisibility */);
-                if (DEBUG) Slog.d(TAG, "Updated config=" + targetActivity.getConfiguration());
+                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Updated config=%s",
+                        targetActivity.getConfiguration());
             }
         } else {
             // Create the activity record. Because the activity is invisible, this doesn't really
@@ -131,7 +133,7 @@
         }
 
         if (!targetActivity.attachedToProcess()) {
-            if (DEBUG) Slog.d(TAG, "Real start recents");
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Real start recents");
             mStackSupervisor.startSpecificActivityLocked(targetActivity, false /* andResume */,
                     false /* checkConfig */);
             // Make sure the activity won't be involved in transition.
@@ -155,7 +157,7 @@
     }
 
     void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) {
-        if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + mTargetIntent);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent);
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
 
         // TODO(multi-display) currently only support recents animation in default display.
@@ -163,8 +165,9 @@
                 mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
         if (!mWindowManager.canStartRecentsAnimation()) {
             notifyAnimationCancelBeforeStart(recentsAnimationRunner);
-            if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition="
-                        + dc.mAppTransition.getAppTransition());
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "Can't start recents animation, nextAppTransition=%s",
+                        dc.mAppTransition.getAppTransition());
             return;
         }
 
@@ -178,7 +181,8 @@
             mRestoreTargetBehindStack = display.getStackAbove(targetStack);
             if (mRestoreTargetBehindStack == null) {
                 notifyAnimationCancelBeforeStart(recentsAnimationRunner);
-                if (DEBUG) Slog.d(TAG, "No stack above target stack=" + targetStack);
+                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                        "No stack above target stack=%s", targetStack);
                 return;
             }
         }
@@ -201,8 +205,8 @@
             if (hasExistingActivity) {
                 // Move the recents activity into place for the animation if it is not top most
                 mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
-                if (DEBUG) Slog.d(TAG, "Moved stack=" + targetStack + " behind stack="
-                            + mDefaultDisplay.getStackAbove(targetStack));
+                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
+                        targetStack, mDefaultDisplay.getStackAbove(targetStack));
 
                 // If there are multiple tasks in the target stack (ie. the home stack, with 3p
                 // and default launchers coexisting), then move the task to the top as a part of
@@ -220,17 +224,15 @@
                         mTargetActivityType);
                 targetActivity = getTargetActivity(targetStack);
                 mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
-                if (DEBUG) {
-                    Slog.d(TAG, "Moved stack=" + targetStack + " behind stack="
-                            + mDefaultDisplay.getStackAbove(targetStack));
-                }
+                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved stack=%s behind stack=%s",
+                        targetStack, mDefaultDisplay.getStackAbove(targetStack));
 
                 mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                 mWindowManager.executeAppTransition();
 
                 // TODO: Maybe wait for app to draw in this particular case?
 
-                if (DEBUG) Slog.d(TAG, "Started intent=" + mTargetIntent);
+                ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Started intent=%s", mTargetIntent);
             }
 
             // Mark the target activity as launch-behind to bump its visibility for the
@@ -268,9 +270,9 @@
     private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode,
             boolean sendUserLeaveHint) {
         synchronized (mService.mGlobalLock) {
-            if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
-                    + mWindowManager.getRecentsAnimationController()
-                    + " reorderMode=" + reorderMode);
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "onAnimationFinished(): controller=%s reorderMode=%d",
+                            mWindowManager.getRecentsAnimationController(), reorderMode);
 
             // Unregister for stack order changes
             mDefaultDisplay.unregisterStackOrderChangedListener(this);
@@ -308,9 +310,10 @@
                     final ActivityRecord targetActivity = targetStack != null
                             ? targetStack.isInStackLocked(mLaunchedTargetActivity)
                             : null;
-                    if (DEBUG) Slog.d(TAG, "onAnimationFinished(): targetStack=" + targetStack
-                            + " targetActivity=" + targetActivity
-                            + " mRestoreTargetBehindStack=" + mRestoreTargetBehindStack);
+                    ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                            "onAnimationFinished(): targetStack=%s targetActivity=%s "
+                                    + "mRestoreTargetBehindStack=%s",
+                            targetStack, targetActivity, mRestoreTargetBehindStack);
                     if (targetActivity == null) {
                         return;
                     }
@@ -333,25 +336,28 @@
                             targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
                         }
 
-                        if (DEBUG) {
+                        if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
                             final ActivityStack topStack = getTopNonAlwaysOnTopStack();
                             if (topStack != targetStack) {
-                                Slog.w(TAG, "Expected target stack=" + targetStack
-                                        + " to be top most but found stack=" + topStack);
+                                ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS,
+                                        "Expected target stack=%s"
+                                        + " to be top most but found stack=%s",
+                                        targetStack, topStack);
                             }
                         }
                     } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){
                         // Restore the target stack to its previous position
                         final ActivityDisplay display = targetActivity.getDisplay();
                         display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack);
-                        if (DEBUG) {
+                        if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) {
                             final ActivityStack aboveTargetStack =
                                     mDefaultDisplay.getStackAbove(targetStack);
                             if (mRestoreTargetBehindStack != null
                                     && aboveTargetStack != mRestoreTargetBehindStack) {
-                                Slog.w(TAG, "Expected target stack=" + targetStack
-                                        + " to restored behind stack=" + mRestoreTargetBehindStack
-                                        + " but it is behind stack=" + aboveTargetStack);
+                                ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS,
+                                        "Expected target stack=%s to restored behind stack=%s but"
+                                                + " it is behind stack=%s",
+                                        targetStack, mRestoreTargetBehindStack, aboveTargetStack);
                             }
                         }
                     } else {
@@ -402,7 +408,7 @@
 
     @Override
     public void onStackOrderChanged(ActivityStack stack) {
-        if (DEBUG) Slog.d(TAG, "onStackOrderChanged(): stack=" + stack);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onStackOrderChanged(): stack=%s", stack);
         if (mDefaultDisplay.getIndexOf(stack) == -1 || !stack.shouldBeVisible(null)) {
             // The stack is not visible, so ignore this change
             return;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 795a2ca..bd27905 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,8 +29,8 @@
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
 import static com.android.server.wm.BoundsAnimationController.FADE_IN;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
 
 import android.annotation.IntDef;
@@ -57,6 +57,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.LocalServices;
 import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.InsetUtils;
@@ -65,6 +66,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.stream.Collectors;
 
 /**
  * Controls a single instance of the remote driven recents animation. In particular, this allows
@@ -178,8 +180,8 @@
 
         @Override
         public TaskSnapshot screenshotTask(int taskId) {
-            if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
-                    + " mCanceled=" + mCanceled);
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "screenshotTask(%d): mCanceled=%b", taskId, mCanceled);
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mService.getWindowManagerLock()) {
@@ -208,8 +210,8 @@
 
         @Override
         public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
-            if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
-                    + " mCanceled=" + mCanceled);
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mService.getWindowManagerLock()) {
@@ -250,8 +252,8 @@
 
         @Override
         public void setInputConsumerEnabled(boolean enabled) {
-            if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):"
-                    + " mCanceled=" + mCanceled);
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "setInputConsumerEnabled(%s): mCanceled=%b", enabled, mCanceled);
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mService.getWindowManagerLock()) {
@@ -392,8 +394,8 @@
         final AppWindowToken recentsComponentAppToken =
                 targetStack.getTopChild().getTopFullscreenAppToken();
         if (recentsComponentAppToken != null) {
-            if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
-                    + recentsComponentAppToken.getName() + ")");
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "setHomeApp(%s)", recentsComponentAppToken.getName());
             mTargetAppToken = recentsComponentAppToken;
             if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
                 mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
@@ -418,7 +420,7 @@
 
     @VisibleForTesting
     AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")");
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
         final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
                 isRecentTaskInvisible);
         task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
@@ -429,8 +431,8 @@
 
     @VisibleForTesting
     void removeAnimation(TaskAnimationAdapter taskAdapter) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation("
-                + taskAdapter.mTask.mTaskId + ")");
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                "removeAnimation(%d)", taskAdapter.mTask.mTaskId);
         taskAdapter.mTask.setCanAffectSystemUiFlags(true);
         taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
         mPendingAnimations.remove(taskAdapter);
@@ -438,14 +440,14 @@
 
     @VisibleForTesting
     void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeWallpaperAnimation()");
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeWallpaperAnimation()");
         wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter);
         mPendingWallpaperAnimations.remove(wallpaperAdapter);
     }
 
     void startAnimation() {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
-                + " mCanceled=" + mCanceled);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                "startAnimation(): mPendingStart=%b mCanceled=%b", mPendingStart, mCanceled);
         if (!mPendingStart || mCanceled) {
             // Skip starting if we've already started or canceled the animation
             return;
@@ -483,13 +485,10 @@
             }
             mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
                     minimizedHomeBounds);
-            if (DEBUG_RECENTS_ANIMATIONS) {
-                Slog.d(TAG, "startAnimation(): Notify animation start:");
-                for (int i = 0; i < mPendingAnimations.size(); i++) {
-                    final Task task = mPendingAnimations.get(i).mTask;
-                    Slog.d(TAG, "\t" + task.mTaskId);
-                }
-            }
+            ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                    "startAnimation(): Notify animation start: %s",
+                    mPendingAnimations.stream()
+                            .map(anim->anim.mTask.mTaskId).collect(Collectors.toList()));
         } catch (RemoteException e) {
             Slog.e(TAG, "Failed to start recents animation", e);
         }
@@ -513,7 +512,7 @@
     }
 
     private RemoteAnimationTarget[] createWallpaperAnimations() {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()");
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "createWallpaperAnimations()");
         return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
                 adapter -> {
                     synchronized (mService.mGlobalLock) {
@@ -533,7 +532,7 @@
     }
 
     private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
         synchronized (mService.getWindowManagerLock()) {
             if (mCanceled) {
                 // We've already canceled the animation
@@ -627,9 +626,7 @@
         mRecentScreenshotAnimator = new SurfaceAnimator(
                 animatable,
                 () -> {
-                    if (DEBUG_RECENTS_ANIMATIONS) {
-                        Slog.d(TAG, "mRecentScreenshotAnimator finish");
-                    }
+                    ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish");
                     mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
                 }, mService);
         mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
@@ -637,9 +634,10 @@
     }
 
     void cleanupAnimation(@ReorderMode int reorderMode) {
-        if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
-                "cleanupAnimation(): Notify animation finished mPendingAnimations="
-                        + mPendingAnimations.size() + " reorderMode=" + reorderMode);
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                        "cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
+                                + "reorderMode=%d",
+                        mPendingAnimations.size(), reorderMode);
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
             if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 87bda4a..2b2ae92 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -17,9 +17,8 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -39,6 +38,8 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.util.FastPrintWriter;
+import com.android.server.protolog.ProtoLogImpl;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.InsetUtils;
 
@@ -51,7 +52,6 @@
  */
 class RemoteAnimationController implements DeathRecipient {
     private static final String TAG = TAG_WITH_CLASS_NAME
-            || (DEBUG_REMOTE_ANIMATIONS && !DEBUG_APP_TRANSITIONS)
                     ? "RemoteAnimationController" : TAG_WM;
     private static final long TIMEOUT_MS = 2000;
 
@@ -86,8 +86,8 @@
      */
     RemoteAnimationRecord createRemoteAnimationRecord(AppWindowToken appWindowToken,
             Point position, Rect stackBounds, Rect startBounds) {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAnimationAdapter(): token="
-                + appWindowToken);
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): token=%s",
+                appWindowToken);
         final RemoteAnimationRecord adapters =
                 new RemoteAnimationRecord(appWindowToken, position, stackBounds, startBounds);
         mPendingAnimations.add(adapters);
@@ -98,11 +98,11 @@
      * Called when the transition is ready to be started, and all leashes have been set up.
      */
     void goodToGo() {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo()");
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo()");
         if (mPendingAnimations.isEmpty() || mCanceled) {
-            if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): Animation finished already,"
-                    + " canceled=" + mCanceled
-                    + " mPendingAnimations=" + mPendingAnimations.size());
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
+                    "goodToGo(): Animation finished already, canceled=%s mPendingAnimations=%d",
+                    mCanceled, mPendingAnimations.size());
             onAnimationFinished();
             return;
         }
@@ -115,7 +115,7 @@
         // Create the app targets
         final RemoteAnimationTarget[] appTargets = createAppAnimations();
         if (appTargets.length == 0) {
-            if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "goodToGo(): No apps to animate");
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "goodToGo(): No apps to animate");
             onAnimationFinished();
             return;
         }
@@ -131,8 +131,8 @@
                 Slog.e(TAG, "Failed to start remote animation", e);
                 onAnimationFinished();
             }
-            if (DEBUG_REMOTE_ANIMATIONS) {
-                Slog.d(TAG, "startAnimation(): Notify animation start:");
+            if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:");
                 writeStartDebugStatement();
             }
         });
@@ -140,7 +140,7 @@
     }
 
     void cancelAnimation(String reason) {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
         synchronized (mService.getWindowManagerLock()) {
             if (mCanceled) {
                 return;
@@ -152,28 +152,28 @@
     }
 
     private void writeStartDebugStatement() {
-        Slog.i(TAG, "Starting remote animation");
+        ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Starting remote animation");
         final StringWriter sw = new StringWriter();
         final FastPrintWriter pw = new FastPrintWriter(sw);
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             mPendingAnimations.get(i).mAdapter.dump(pw, "");
         }
         pw.close();
-        Slog.i(TAG, sw.toString());
+        ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "%s", sw.toString());
     }
 
     private RemoteAnimationTarget[] createAppAnimations() {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createAppAnimations()");
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAppAnimations()");
         final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
             final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
             if (target != null) {
-                if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tAdd token=" + wrappers.mAppWindowToken);
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd token=%s", wrappers.mAppWindowToken);
                 targets.add(target);
             } else {
-                if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tRemove token="
-                        + wrappers.mAppWindowToken);
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove token=%s",
+                        wrappers.mAppWindowToken);
 
                 // We can't really start an animation but we still need to make sure to finish the
                 // pending animation that was started by SurfaceAnimator
@@ -194,7 +194,7 @@
     }
 
     private RemoteAnimationTarget[] createWallpaperAnimations() {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()");
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createWallpaperAnimations()");
         return WallpaperAnimationAdapter.startWallpaperAnimations(mService,
                 mRemoteAnimationAdapter.getDuration(),
                 mRemoteAnimationAdapter.getStatusBarTransitionDelay(),
@@ -207,15 +207,15 @@
     }
 
     private void onAnimationFinished() {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationFinished(): mPendingAnimations="
-                + mPendingAnimations.size());
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationFinished(): mPendingAnimations=%d",
+                mPendingAnimations.size());
         mHandler.removeCallbacks(mTimeoutRunnable);
         synchronized (mService.mGlobalLock) {
             unlinkToDeathOfRunner();
             releaseFinishedCallback();
             mService.openSurfaceTransaction();
             try {
-                if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG,
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS,
                         "onAnimationFinished(): Notify animation finished:");
                 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
                     final RemoteAnimationRecord adapters = mPendingAnimations.get(i);
@@ -228,14 +228,14 @@
                                 .onAnimationFinished(adapters.mThumbnailAdapter);
                     }
                     mPendingAnimations.remove(i);
-                    if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\tapp=" + adapters.mAppWindowToken);
+                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tapp=%s", adapters.mAppWindowToken);
                 }
 
                 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
                     final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i);
                     adapter.getLeashFinishedCallback().onAnimationFinished(adapter);
                     mPendingWallpaperAnimations.remove(i);
-                    if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "\twallpaper=" + adapter.getToken());
+                    ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken());
                 }
             } catch (Exception e) {
                 Slog.e(TAG, "Failed to finish remote animation", e);
@@ -245,7 +245,7 @@
             }
         }
         setRunningRemoteAnimation(false);
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.i(TAG, "Finishing remote animation");
+        ProtoLog.i(WM_DEBUG_REMOTE_ANIMATIONS, "Finishing remote animation");
     }
 
     private void invokeAnimationCancelled() {
@@ -306,7 +306,7 @@
 
         @Override
         public void onAnimationFinished() throws RemoteException {
-            if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-onAnimationFinished(): mOuter=" + mOuter);
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-onAnimationFinished(): mOuter=%s", mOuter);
             final long token = Binder.clearCallingIdentity();
             try {
                 if (mOuter != null) {
@@ -326,7 +326,7 @@
          * to prevent memory leak.
          */
         void release() {
-            if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "app-release(): mOuter=" + mOuter);
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "app-release(): mOuter=%s", mOuter);
             mOuter = null;
         }
     };
@@ -420,7 +420,7 @@
         @Override
         public void startAnimation(SurfaceControl animationLeash, Transaction t,
                 OnAnimationFinishedCallback finishCallback) {
-            if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation");
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
 
             // Restore z-layering, position and stack crop until client has a chance to modify it.
             t.setLayer(animationLeash, mRecord.mAppWindowToken.getPrefixOrderIndex());
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 4365d03..78fcb37 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -29,20 +29,19 @@
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
 import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
 import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.WINDOW_FREEZE_TIMEOUT;
@@ -50,7 +49,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
-import static com.android.server.wm.WindowManagerService.logSurface;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
@@ -80,6 +78,7 @@
 import android.view.WindowManager;
 
 import com.android.server.EventLogTags;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -195,8 +194,8 @@
             mTopFocusedDisplayId = topFocusedDisplayId;
             mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
             mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
-            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "New topFocusedDisplayId="
-                    + topFocusedDisplayId);
+            ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d",
+                    topFocusedDisplayId);
         }
         return changed;
     }
@@ -457,13 +456,13 @@
     }
 
     void removeReplacedWindows() {
-        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION removeReplacedWindows");
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION removeReplacedWindows");
         mWmService.openSurfaceTransaction();
         try {
             forAllWindows(sRemoveReplacedWindowsConsumer, true /* traverseTopToBottom */);
         } finally {
             mWmService.closeSurfaceTransaction("removeReplacedWindows");
-            if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION removeReplacedWindows");
         }
     }
 
@@ -539,8 +538,8 @@
                 Slog.w(TAG_WM,
                         "Looks like we have reclaimed some memory, clearing surface for retry.");
                 if (surfaceController != null) {
-                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
-                            "RECOVER DESTROY", false);
+                    ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
+                            "SURFACE RECOVER DESTROY: %s",  winAnimator.mWin);
                     winAnimator.destroySurface();
                     if (winAnimator.mWin.mAppToken != null) {
                         winAnimator.mWin.mAppToken.removeStartingWindow();
@@ -651,8 +650,11 @@
 
         handleResizingWindows();
 
-        if (DEBUG_ORIENTATION && mWmService.mDisplayFrozen) Slog.v(TAG,
-                "With display frozen, orientationChangeComplete=" + mOrientationChangeComplete);
+        if (mWmService.mDisplayFrozen) {
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                    "With display frozen, orientationChangeComplete=%b",
+                    mOrientationChangeComplete);
+        }
         if (mOrientationChangeComplete) {
             if (mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
                 mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
@@ -714,7 +716,7 @@
         }
 
         if (mUpdateRotation) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
+            ProtoLog.d(WM_DEBUG_ORIENTATION, "Performing post-rotate rotation");
             mUpdateRotation = updateRotationUnchecked();
         }
 
@@ -868,29 +870,26 @@
         final int privateflags = attrs.privateFlags;
         boolean displayHasContent = false;
 
-        if (DEBUG_KEEP_SCREEN_ON) {
-            Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked w: " + w
-                + ", w.mHasSurface: " + w.mHasSurface
-                + ", w.isOnScreen(): " + onScreen
-                + ", w.isDisplayedLw(): " + w.isDisplayedLw()
-                + ", w.mAttrs.userActivityTimeout: " + w.mAttrs.userActivityTimeout);
-        }
+        ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
+                    "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w"
+                            + ".isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
+                    w, w.mHasSurface, onScreen, w.isDisplayedLw(), w.mAttrs.userActivityTimeout);
         if (w.mHasSurface && onScreen) {
             if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
                 mUserActivityTimeout = w.mAttrs.userActivityTimeout;
-                if (DEBUG_KEEP_SCREEN_ON) {
-                    Slog.d(TAG, "mUserActivityTimeout set to " + mUserActivityTimeout);
-                }
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "mUserActivityTimeout set to %d",
+                        mUserActivityTimeout);
             }
         }
         if (w.mHasSurface && canBeSeen) {
             if ((attrFlags & FLAG_KEEP_SCREEN_ON) != 0) {
                 mHoldScreen = w.mSession;
                 mHoldScreenWindow = w;
-            } else if (DEBUG_KEEP_SCREEN_ON && w == mWmService.mLastWakeLockHoldingWindow) {
-                Slog.d(TAG_KEEP_SCREEN_ON, "handleNotObscuredLocked: " + w + " was holding "
-                        + "screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by"
-                        + Debug.getCallers(10));
+            } else if (w == mWmService.mLastWakeLockHoldingWindow) {
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
+                        "handleNotObscuredLocked: %s was holding screen wakelock but no longer "
+                                + "has FLAG_KEEP_SCREEN_ON!!! called by%s",
+                        w, Debug.getCallers(10));
             }
             if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
                 mScreenBrightness = w.mAttrs.screenBrightness;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index cbaf098..157bd3b 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,10 +16,9 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
 import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
@@ -27,6 +26,7 @@
 
 import android.content.Context;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -39,8 +39,38 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.io.PrintWriter;
 
+/**
+ * This class handles the rotation animation when the device is rotated.
+ *
+ * <p>
+ * The screen rotation animation is composed of 4 different part:
+ * <ul>
+ * <li> The screenshot: <p>
+ *     A screenshot of the whole screen prior the change of orientation is taken to hide the
+ *     element resizing below. The screenshot is then animated to rotate and cross-fade to
+ *     the new orientation with the content in the new orientation.
+ *
+ * <li> The windows on the display: <p>y
+ *      Once the device is rotated, the screen and its content are in the new orientation. The
+ *      animation first rotate the new content into the old orientation to then be able to
+ *      animate to the new orientation
+ *
+ * <li> The exiting Blackframe: <p>
+ *     Because the change of orientation might change the width and height of the content (i.e
+ *     when rotating from portrait to landscape) we "crop" the new content using black frames
+ *     around the screenshot so the new content does not go beyond the screenshot's bounds
+ *
+ * <li> The entering Blackframe: <p>
+ *     The enter Blackframe is similar to the exit Blackframe but is only used when a custom
+ *     rotation animation is used and matches the new content size instead of the screenshot.
+ * </ul>
+ *
+ * Each part has its own Surface which are then animated by {@link SurfaceAnimator}s.
+ */
 class ScreenRotationAnimation {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM;
 
@@ -66,6 +96,8 @@
     private final Matrix mSnapshotFinalMatrix = new Matrix();
     private final Matrix mExitFrameFinalMatrix = new Matrix();
     private final WindowManagerService mService;
+    private SurfaceControl mEnterBlackFrameLayer;
+    private SurfaceControl mRotationLayer;
     private SurfaceControl mSurfaceControl;
     private BlackFrame mEnteringBlackFrame;
     private int mWidth, mHeight;
@@ -81,15 +113,14 @@
     // rotations.
     private Animation mRotateExitAnimation;
     private Animation mRotateEnterAnimation;
+    private Animation mRotateAlphaAnimation;
     private boolean mStarted;
     private boolean mAnimRunning;
     private boolean mFinishAnimReady;
     private long mFinishAnimStartTime;
     private boolean mForceDefaultOrientation;
     private BlackFrame mExitingBlackFrame;
-    private boolean mMoreRotateEnter;
-    private boolean mMoreRotateExit;
-    private long mHalfwayPoint;
+    private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
 
     public ScreenRotationAnimation(Context context, DisplayContent displayContent,
             boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
@@ -126,11 +157,23 @@
         mOriginalRotation = originalRotation;
         mOriginalWidth = originalWidth;
         mOriginalHeight = originalHeight;
+        mSurfaceRotationAnimationController = new SurfaceRotationAnimationController();
 
         final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
         try {
-            mSurfaceControl = displayContent.makeOverlay()
+            mRotationLayer = displayContent.makeOverlay()
+                    .setName("RotationLayer")
+                    .setContainerLayer()
+                    .build();
+
+            mEnterBlackFrameLayer = displayContent.makeOverlay()
+                    .setName("EnterBlackFrameLayer")
+                    .setContainerLayer()
+                    .build();
+
+            mSurfaceControl = displayContent.makeSurface(null)
                     .setName("ScreenshotSurface")
+                    .setParent(mRotationLayer)
                     .setBufferSize(mWidth, mHeight)
                     .setSecure(isSecure)
                     .build();
@@ -160,8 +203,10 @@
                 if (gb.containsSecureLayers()) {
                     t.setSecure(mSurfaceControl, true);
                 }
+                t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
                 t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
                 t.setAlpha(mSurfaceControl, 0);
+                t.show(mRotationLayer);
                 t.show(mSurfaceControl);
             } else {
                 Slog.w(TAG, "Unable to take screenshot of display " + displayId);
@@ -171,10 +216,8 @@
             Slog.w(TAG, "Unable to allocate freeze surface", e);
         }
 
-        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-            Slog.i(TAG_WM,
-                    "  FREEZE " + mSurfaceControl + ": CREATE");
-        }
+        ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
+                    "  FREEZE %s: CREATE", mSurfaceControl);
         setRotation(t, originalRotation);
         t.apply();
     }
@@ -211,22 +254,26 @@
         return mSurfaceControl != null;
     }
 
-    private void setSnapshotTransform(SurfaceControl.Transaction t, Matrix matrix, float alpha) {
-        if (mSurfaceControl != null) {
-            matrix.getValues(mTmpFloats);
-            float x = mTmpFloats[Matrix.MTRANS_X];
-            float y = mTmpFloats[Matrix.MTRANS_Y];
-            if (mForceDefaultOrientation) {
-                mDisplayContent.getBounds(mCurrentDisplayRect);
-                x -= mCurrentDisplayRect.left;
-                y -= mCurrentDisplayRect.top;
-            }
-            t.setPosition(mSurfaceControl, x, y);
-            t.setMatrix(mSurfaceControl,
-                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
-                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            t.setAlpha(mSurfaceControl, alpha);
+    private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
+        if (mRotationLayer == null) {
+            return;
         }
+        matrix.getValues(mTmpFloats);
+        float x = mTmpFloats[Matrix.MTRANS_X];
+        float y = mTmpFloats[Matrix.MTRANS_Y];
+        if (mForceDefaultOrientation) {
+            mDisplayContent.getBounds(mCurrentDisplayRect);
+            x -= mCurrentDisplayRect.left;
+            y -= mCurrentDisplayRect.top;
+        }
+        t.setPosition(mRotationLayer, x, y);
+        t.setMatrix(mRotationLayer,
+                mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+                mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+
+        t.setAlpha(mSurfaceControl, (float) 1.0);
+        t.setAlpha(mRotationLayer, (float) 1.0);
+        t.show(mRotationLayer);
     }
 
     public void printTo(String prefix, PrintWriter pw) {
@@ -237,7 +284,9 @@
         if (mExitingBlackFrame != null) {
             mExitingBlackFrame.printTo(prefix + "  ", pw);
         }
-        pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame);
+        pw.print(prefix);
+        pw.print("mEnteringBlackFrame=");
+        pw.println(mEnteringBlackFrame);
         if (mEnteringBlackFrame != null) {
             mEnteringBlackFrame.printTo(prefix + "  ", pw);
         }
@@ -283,7 +332,7 @@
         int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
         createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
-        setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f);
+        setRotationTransform(t, mSnapshotInitialMatrix);
     }
 
     /**
@@ -304,6 +353,9 @@
         // Figure out how the screen has moved from the original rotation.
         int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
 
+        mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
+                com.android.internal.R.anim.screen_rotate_alpha);
+
         final boolean customAnim;
         if (exitAnim != 0 && enterAnim != 0) {
             customAnim = true;
@@ -353,6 +405,8 @@
         mRotateExitAnimation.scaleCurrentDuration(animationScale);
         mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
         mRotateEnterAnimation.scaleCurrentDuration(animationScale);
+        mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
+        mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
 
         if (!customAnim && mExitingBlackFrame == null) {
             try {
@@ -373,13 +427,12 @@
                     outer = mCurrentDisplayRect;
                     inner = mOriginalDisplayRect;
                 } else {
-                    outer = new Rect(-mOriginalWidth * 1, -mOriginalHeight * 1,
-                            mOriginalWidth * 2, mOriginalHeight * 2);
-                    inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
+                    outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
+                    inner = new Rect(0, 0, mWidth, mHeight);
                 }
                 mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
-                        SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation);
-                mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix);
+                        SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
+                        mRotationLayer);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             }
@@ -387,16 +440,17 @@
 
         if (customAnim && mEnteringBlackFrame == null) {
             try {
-                Rect outer = new Rect(-finalWidth * 1, -finalHeight * 1,
+                Rect outer = new Rect(-finalWidth, -finalHeight,
                         finalWidth * 2, finalHeight * 2);
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
                 mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
-                        SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
+                        SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false, mEnterBlackFrameLayer);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
             }
         }
 
+        mSurfaceRotationAnimationController.startAnimation();
         return true;
     }
 
@@ -421,14 +475,27 @@
     }
 
     public void kill() {
+        if (mSurfaceRotationAnimationController != null) {
+            mSurfaceRotationAnimationController.cancel();
+            mSurfaceRotationAnimationController = null;
+        }
         if (mSurfaceControl != null) {
-            if (SHOW_TRANSACTIONS ||
-                    SHOW_SURFACE_ALLOC) {
-                Slog.i(TAG_WM,
-                        "  FREEZE " + mSurfaceControl + ": DESTROY");
-            }
-            mService.mTransactionFactory.get().remove(mSurfaceControl).apply();
+            ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "  FREEZE %s: DESTROY", mSurfaceControl);
             mSurfaceControl = null;
+            SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+            if (mRotationLayer != null) {
+                if (mRotationLayer.isValid()) {
+                    t.remove(mRotationLayer);
+                }
+                mRotationLayer = null;
+            }
+            if (mEnterBlackFrameLayer != null) {
+                if (mEnterBlackFrameLayer.isValid()) {
+                    t.remove(mEnterBlackFrameLayer);
+                }
+                mEnterBlackFrameLayer = null;
+            }
+            t.apply();
         }
         if (mExitingBlackFrame != null) {
             mExitingBlackFrame.kill();
@@ -446,124 +513,186 @@
             mRotateEnterAnimation.cancel();
             mRotateEnterAnimation = null;
         }
+        if (mRotateAlphaAnimation != null) {
+            mRotateAlphaAnimation.cancel();
+            mRotateAlphaAnimation = null;
+        }
     }
 
     public boolean isAnimating() {
-        return hasAnimations();
+        return mSurfaceRotationAnimationController != null
+                && mSurfaceRotationAnimationController.isAnimating();
     }
 
     public boolean isRotating() {
         return mCurRotation != mOriginalRotation;
     }
 
-    private boolean hasAnimations() {
-        return mRotateEnterAnimation != null || mRotateExitAnimation != null;
-    }
-
-    private boolean stepAnimation(long now) {
-        if (now > mHalfwayPoint) {
-            mHalfwayPoint = Long.MAX_VALUE;
-        }
-        if (mFinishAnimReady && mFinishAnimStartTime < 0) {
-            mFinishAnimStartTime = now;
-        }
-
-        mMoreRotateExit = false;
-        if (mRotateExitAnimation != null) {
-            mMoreRotateExit = mRotateExitAnimation.getTransformation(now,
-                    mRotateExitTransformation);
-        }
-
-        mMoreRotateEnter = false;
-        if (mRotateEnterAnimation != null) {
-            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now,
-                    mRotateEnterTransformation);
-        }
-
-        if (!mMoreRotateExit) {
-            if (mRotateExitAnimation != null) {
-                mRotateExitAnimation.cancel();
-                mRotateExitAnimation = null;
-                mRotateExitTransformation.clear();
-            }
-        }
-
-        if (!mMoreRotateEnter) {
-            if (mRotateEnterAnimation != null) {
-                mRotateEnterAnimation.cancel();
-                mRotateEnterAnimation = null;
-                mRotateEnterTransformation.clear();
-            }
-        }
-
-        mExitTransformation.set(mRotateExitTransformation);
-        mEnterTransformation.set(mRotateEnterTransformation);
-
-        final boolean more = mMoreRotateEnter || mMoreRotateExit
-                || !mFinishAnimReady;
-
-        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
-
-        return more;
-    }
-
-    void updateSurfaces(SurfaceControl.Transaction t) {
-        if (!mStarted) {
-            return;
-        }
-
-        if (mSurfaceControl != null) {
-            if (!mMoreRotateExit) {
-                t.hide(mSurfaceControl);
-            }
-        }
-
-        if (mExitingBlackFrame != null) {
-            if (!mMoreRotateExit) {
-                mExitingBlackFrame.hide(t);
-            } else {
-                mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(),
-                        mFrameInitialMatrix);
-                mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix);
-                if (mForceDefaultOrientation) {
-                    mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha());
-                }
-            }
-        }
-
-        if (mEnteringBlackFrame != null) {
-            if (!mMoreRotateEnter) {
-                mEnteringBlackFrame.hide(t);
-            } else {
-                mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix());
-            }
-        }
-
-        t.setEarlyWakeup();
-        setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha());
-    }
-
-    public boolean stepAnimationLocked(long now) {
-        if (!hasAnimations()) {
-            mFinishAnimReady = false;
-            return false;
-        }
-
-        if (!mAnimRunning) {
-            if (mRotateEnterAnimation != null) {
-                mRotateEnterAnimation.setStartTime(now);
-            }
-            if (mRotateExitAnimation != null) {
-                mRotateExitAnimation.setStartTime(now);
-            }
-            mAnimRunning = true;
-            mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
-        }
-
-        return stepAnimation(now);
-    }
-
     public Transformation getEnterTransformation() {
         return mEnterTransformation;
     }
+
+    /**
+     * Utility class that runs a {@link ScreenRotationAnimation} on the {@link
+     * SurfaceAnimationRunner}.
+     * <p>
+     * The rotation animation is divided into the following hierarchy:
+     * <ul>
+     * <li> A first rotation layer, containing the blackframes. This layer is animated by the
+     * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
+     *     <ul>
+     *         <li> A child layer containing the screenshot on which is added an animation of it's
+     *     alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
+     *     </ul>
+     * <li> A second rotation layer used when custom animations are passed in
+     * {@link ScreenRotationAnimation#startAnimation(
+     *     SurfaceControl.Transaction, long, float, int, int, int, int)}.
+     * </ul>
+     * <p>
+     * Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
+     * this three {@link SurfaceControl}s which then delegates the animation to the
+     * {@link ScreenRotationAnimation}.
+     */
+    class SurfaceRotationAnimationController {
+        private SurfaceAnimator mDisplayAnimator;
+        private SurfaceAnimator mEnterBlackFrameAnimator;
+        private SurfaceAnimator mScreenshotRotationAnimator;
+        private SurfaceAnimator mRotateScreenAnimator;
+        private final Runnable mNoopCallback = () -> { // b/141177184
+        };
+
+        /**
+         * Start the rotation animation of the display and the screenshot on the
+         * {@link SurfaceAnimationRunner}.
+         */
+        void startAnimation() {
+            mRotateScreenAnimator = startScreenshotAlphaAnimation();
+            mDisplayAnimator = startDisplayRotation();
+            if (mExitingBlackFrame != null) {
+                mScreenshotRotationAnimator = startScreenshotRotationAnimation();
+            }
+            if (mEnteringBlackFrame != null) {
+                mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
+            }
+        }
+
+        private SimpleSurfaceAnimatable.Builder initializeBuilder() {
+            return new SimpleSurfaceAnimatable.Builder()
+                    .setPendingTransactionSupplier(mDisplayContent::getPendingTransaction)
+                    .setCommitTransactionRunnable(mDisplayContent::commitPendingTransaction)
+                    .setAnimationLeashSupplier(mDisplayContent::makeOverlay);
+        }
+
+        private SurfaceAnimator startDisplayRotation() {
+            return startAnimation(initializeBuilder()
+                            .setAnimationLeashParent(mDisplayContent.getSurfaceControl())
+                            .setSurfaceControl(mDisplayContent.getWindowingLayer())
+                            .setParentSurfaceControl(mDisplayContent.getSurfaceControl())
+                            .setWidth(mDisplayContent.getSurfaceWidth())
+                            .setHeight(mDisplayContent.getSurfaceHeight())
+                            .build(),
+                    createWindowAnimationSpec(mRotateEnterAnimation),
+                    this::cancel);
+        }
+
+        private SurfaceAnimator startScreenshotAlphaAnimation() {
+            return startAnimation(initializeBuilder()
+                            .setSurfaceControl(mSurfaceControl)
+                            .setAnimationLeashParent(mRotationLayer)
+                            .setWidth(mWidth)
+                            .setHeight(mHeight)
+                            .build(),
+                    createWindowAnimationSpec(mRotateAlphaAnimation),
+                    mNoopCallback);
+        }
+
+        private SurfaceAnimator startEnterBlackFrameAnimation() {
+            return startAnimation(initializeBuilder()
+                            .setSurfaceControl(mEnterBlackFrameLayer)
+                            .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
+                            .build(),
+                    createWindowAnimationSpec(mRotateEnterAnimation),
+                    mNoopCallback);
+        }
+
+        private SurfaceAnimator startScreenshotRotationAnimation() {
+            return startAnimation(initializeBuilder()
+                            .setSurfaceControl(mRotationLayer)
+                            .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
+                            .build(),
+                    createWindowAnimationSpec(mRotateExitAnimation),
+                    this::onAnimationEnd);
+        }
+
+        private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
+            return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
+                    false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
+        }
+
+        /**
+         * Start an animation defined by animationSpec on a new {@link SurfaceAnimator}.
+         *
+         * @param animatable The animatable used for the animation.
+         * @param animationSpec                The spec of the animation.
+         * @param animationFinishedCallback    Callback passed to the {@link SurfaceAnimator} and
+         *                                    called when the animation finishes.
+         * @return The newly created {@link SurfaceAnimator} that as been started.
+         */
+        private SurfaceAnimator startAnimation(
+                SurfaceAnimator.Animatable animatable,
+                LocalAnimationAdapter.AnimationSpec animationSpec,
+                Runnable animationFinishedCallback) {
+            SurfaceAnimator animator = new SurfaceAnimator(
+                    animatable, animationFinishedCallback, mService);
+
+            LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
+                    animationSpec, mService.mSurfaceAnimationRunner);
+
+            animator.startAnimation(mDisplayContent.getPendingTransaction(),
+                    localAnimationAdapter, false);
+            return animator;
+        }
+
+        private void onAnimationEnd() {
+            mEnterBlackFrameAnimator = null;
+            mScreenshotRotationAnimator = null;
+            mRotateScreenAnimator = null;
+            mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
+            kill();
+            mService.updateRotation(false, false);
+            AccessibilityController accessibilityController = mService.mAccessibilityController;
+
+            if (accessibilityController != null) {
+                // We just finished rotation animation which means we did not
+                // announce the rotation and waited for it to end, announce now.
+                accessibilityController.onRotationChangedLocked(mDisplayContent);
+            }
+        }
+
+        public void cancel() {
+            if (mEnterBlackFrameAnimator != null) {
+                mEnterBlackFrameAnimator.cancelAnimation();
+            }
+
+            if (mScreenshotRotationAnimator != null) {
+                mScreenshotRotationAnimator.cancelAnimation();
+            }
+
+            if (mRotateScreenAnimator != null) {
+                mRotateScreenAnimator.cancelAnimation();
+            }
+
+            if (mDisplayAnimator != null) {
+                mDisplayAnimator.cancelAnimation();
+            }
+        }
+
+        public boolean isAnimating() {
+            return mDisplayAnimator != null && mDisplayAnimator.isAnimating()
+                    || mEnterBlackFrameAnimator != null && mEnterBlackFrameAnimator.isAnimating()
+                    || mRotateScreenAnimator != null && mRotateScreenAnimator.isAnimating()
+                    || mScreenshotRotationAnimator != null
+                    && mScreenshotRotationAnimator.isAnimating();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 72bb355..b047d8f 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -24,9 +24,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
 
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.Nullable;
@@ -56,6 +56,7 @@
 import android.view.WindowManager;
 
 import com.android.internal.os.logging.MetricsLoggerWrapper;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
@@ -478,8 +479,7 @@
                 Slog.v(TAG_WM, "First window added to " + this + ", creating SurfaceSession");
             }
             mSurfaceSession = new SurfaceSession();
-            if (SHOW_TRANSACTIONS) Slog.i(
-                    TAG_WM, "  NEW SURFACE SESSION " + mSurfaceSession);
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "  NEW SURFACE SESSION %s", mSurfaceSession);
             mService.mSessions.add(this);
             if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                 mService.dispatchNewAnimatorScaleLocked(this);
@@ -570,7 +570,7 @@
             Slog.v(TAG_WM, "Last window removed from " + this
                     + ", destroying " + mSurfaceSession);
         }
-        if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  KILL SURFACE SESSION " + mSurfaceSession);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "  KILL SURFACE SESSION %s", mSurfaceSession);
         try {
             mSurfaceSession.kill();
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java b/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java
new file mode 100644
index 0000000..bf5d5e2
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SimpleSurfaceAnimatable.java
@@ -0,0 +1,308 @@
+/*
+ * 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.wm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.view.SurfaceControl;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * An implementation of {@link SurfaceAnimator.Animatable} that is instantiated
+ * using a builder pattern for more convenience over reimplementing the whole interface.
+ * <p>
+ * Use {@link SimpleSurfaceAnimatable.Builder} to create a new instance of this class.
+ *
+ * @see com.android.server.wm.SurfaceAnimator.Animatable
+ */
+public class SimpleSurfaceAnimatable implements SurfaceAnimator.Animatable {
+    private final int mWidth;
+    private final int mHeight;
+    private final boolean mShouldDeferAnimationFinish;
+    private final SurfaceControl mAnimationLeashParent;
+    private final SurfaceControl mSurfaceControl;
+    private final SurfaceControl mParentSurfaceControl;
+    private final Runnable mCommitTransactionRunnable;
+    private final Supplier<SurfaceControl.Builder> mAnimationLeashFactory;
+    private final Supplier<SurfaceControl.Transaction> mPendingTransaction;
+    private final BiConsumer<SurfaceControl.Transaction, SurfaceControl> mOnAnimationLeashCreated;
+    private final Consumer<SurfaceControl.Transaction> mOnAnimationLeashLost;
+    private final Consumer<Runnable> mOnAnimationFinished;
+
+    /**
+     * Use {@link SimpleSurfaceAnimatable.Builder} to create a new instance.
+     */
+    private SimpleSurfaceAnimatable(Builder builder) {
+        mWidth = builder.mWidth;
+        mHeight = builder.mHeight;
+        mShouldDeferAnimationFinish = builder.mShouldDeferAnimationFinish;
+        mAnimationLeashParent = builder.mAnimationLeashParent;
+        mSurfaceControl = builder.mSurfaceControl;
+        mParentSurfaceControl = builder.mParentSurfaceControl;
+        mCommitTransactionRunnable = builder.mCommitTransactionRunnable;
+        mAnimationLeashFactory = builder.mAnimationLeashFactory;
+        mOnAnimationLeashCreated = builder.mOnAnimationLeashCreated;
+        mOnAnimationLeashLost = builder.mOnAnimationLeashLost;
+        mPendingTransaction = builder.mPendingTransactionSupplier;
+        mOnAnimationFinished = builder.mOnAnimationFinished;
+    }
+
+    @NonNull
+    @Override
+    public SurfaceControl.Transaction getPendingTransaction() {
+        return mPendingTransaction.get();
+    }
+
+    @Override
+    public void commitPendingTransaction() {
+        mCommitTransactionRunnable.run();
+    }
+
+    @Override
+    public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
+        if (mOnAnimationLeashCreated != null) {
+            mOnAnimationLeashCreated.accept(t, leash);
+        }
+
+    }
+
+    @Override
+    public void onAnimationLeashLost(SurfaceControl.Transaction t) {
+        if (mOnAnimationLeashLost != null) {
+            mOnAnimationLeashLost.accept(t);
+        }
+    }
+
+    @Override
+    @NonNull
+    public SurfaceControl.Builder makeAnimationLeash() {
+        return mAnimationLeashFactory.get();
+    }
+
+    @Override
+    public SurfaceControl getAnimationLeashParent() {
+        return mAnimationLeashParent;
+    }
+
+    @Override
+    @Nullable
+    public SurfaceControl getSurfaceControl() {
+        return mSurfaceControl;
+    }
+
+    @Override
+    public SurfaceControl getParentSurfaceControl() {
+        return mParentSurfaceControl;
+    }
+
+    @Override
+    public int getSurfaceWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getSurfaceHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
+        if (mOnAnimationFinished != null) {
+            mOnAnimationFinished.accept(endDeferFinishCallback);
+        }
+        return mShouldDeferAnimationFinish;
+    }
+
+    /**
+     * Builder class to create a {@link SurfaceAnimator.Animatable} without having to
+     * create a new class that implements the interface.
+     */
+    static class Builder {
+        private int mWidth = -1;
+        private int mHeight = -1;
+        private boolean mShouldDeferAnimationFinish = false;
+
+        @Nullable
+        private SurfaceControl mAnimationLeashParent = null;
+
+        @Nullable
+        private SurfaceControl mSurfaceControl = null;
+
+        @Nullable
+        private SurfaceControl mParentSurfaceControl = null;
+        private Runnable mCommitTransactionRunnable;
+
+        @Nullable
+        private BiConsumer<SurfaceControl.Transaction, SurfaceControl> mOnAnimationLeashCreated =
+                null;
+
+        @Nullable
+        private Consumer<SurfaceControl.Transaction> mOnAnimationLeashLost = null;
+
+        @Nullable
+        private Consumer<Runnable> mOnAnimationFinished = null;
+
+        @NonNull
+        private Supplier<SurfaceControl.Transaction> mPendingTransactionSupplier;
+
+        @NonNull
+        private Supplier<SurfaceControl.Builder> mAnimationLeashFactory;
+
+        /**
+         * Set the runnable to be called when
+         * {@link SurfaceAnimator.Animatable#commitPendingTransaction()}
+         * is called.
+         *
+         * @see SurfaceAnimator.Animatable#commitPendingTransaction()
+         */
+        public SimpleSurfaceAnimatable.Builder setCommitTransactionRunnable(
+                @NonNull Runnable commitTransactionRunnable) {
+            mCommitTransactionRunnable = commitTransactionRunnable;
+            return this;
+        }
+
+        /**
+         * Set the callback called when
+         * {@link SurfaceAnimator.Animatable#onAnimationLeashCreated(SurfaceControl.Transaction,
+         * SurfaceControl)} is called
+         *
+         * @see SurfaceAnimator.Animatable#onAnimationLeashCreated(SurfaceControl.Transaction,
+         * SurfaceControl)
+         */
+        public SimpleSurfaceAnimatable.Builder setOnAnimationLeashCreated(
+                @Nullable BiConsumer<SurfaceControl.Transaction, SurfaceControl>
+                        onAnimationLeashCreated) {
+            mOnAnimationLeashCreated = onAnimationLeashCreated;
+            return this;
+        }
+
+        /**
+         * Set the callback called when
+         * {@link SurfaceAnimator.Animatable#onAnimationLeashLost(SurfaceControl.Transaction)}
+         * (SurfaceControl.Transaction, SurfaceControl)} is called
+         *
+         * @see SurfaceAnimator.Animatable#onAnimationLeashLost(SurfaceControl.Transaction)
+         */
+        public SimpleSurfaceAnimatable.Builder setOnAnimationLeashLost(
+                @Nullable Consumer<SurfaceControl.Transaction> onAnimationLeashLost) {
+            mOnAnimationLeashLost = onAnimationLeashLost;
+            return this;
+        }
+
+        /**
+         * @see SurfaceAnimator.Animatable#getPendingTransaction()
+         */
+        public Builder setPendingTransactionSupplier(
+                @NonNull Supplier<SurfaceControl.Transaction> pendingTransactionSupplier) {
+            mPendingTransactionSupplier = pendingTransactionSupplier;
+            return this;
+        }
+
+        /**
+         * Set the {@link Supplier} responsible for creating a new animation leash.
+         *
+         * @see SurfaceAnimator.Animatable#makeAnimationLeash()
+         */
+        public SimpleSurfaceAnimatable.Builder setAnimationLeashSupplier(
+                @NonNull Supplier<SurfaceControl.Builder> animationLeashFactory) {
+            mAnimationLeashFactory = animationLeashFactory;
+            return this;
+        }
+
+        /**
+         * @see SurfaceAnimator.Animatable#getAnimationLeashParent()
+         */
+        public SimpleSurfaceAnimatable.Builder setAnimationLeashParent(
+                SurfaceControl animationLeashParent) {
+            mAnimationLeashParent = animationLeashParent;
+            return this;
+        }
+
+        /**
+         * @see SurfaceAnimator.Animatable#getSurfaceControl()
+         */
+        public SimpleSurfaceAnimatable.Builder setSurfaceControl(
+                @NonNull SurfaceControl surfaceControl) {
+            mSurfaceControl = surfaceControl;
+            return this;
+        }
+
+        /**
+         * @see SurfaceAnimator.Animatable#getParentSurfaceControl()
+         */
+        public SimpleSurfaceAnimatable.Builder setParentSurfaceControl(
+                SurfaceControl parentSurfaceControl) {
+            mParentSurfaceControl = parentSurfaceControl;
+            return this;
+        }
+
+        /**
+         * Default to -1.
+         *
+         * @see SurfaceAnimator.Animatable#getSurfaceWidth()
+         */
+        public SimpleSurfaceAnimatable.Builder setWidth(int width) {
+            mWidth = width;
+            return this;
+        }
+
+        /**
+         * Default to -1.
+         *
+         * @see SurfaceAnimator.Animatable#getSurfaceHeight()
+         */
+        public SimpleSurfaceAnimatable.Builder setHeight(int height) {
+            mHeight = height;
+            return this;
+        }
+
+        /**
+         * Set the value returned by
+         * {@link SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)}.
+         *
+         * @param onAnimationFinish will be called with the runnable to execute when the animation
+         *                          needs to be finished.
+         * @see SurfaceAnimator.Animatable#shouldDeferAnimationFinish(Runnable)
+         */
+        public SimpleSurfaceAnimatable.Builder setShouldDeferAnimationFinish(
+                boolean shouldDeferAnimationFinish,
+                @Nullable Consumer<Runnable> onAnimationFinish) {
+            mShouldDeferAnimationFinish = shouldDeferAnimationFinish;
+            mOnAnimationFinished = onAnimationFinish;
+            return this;
+        }
+
+        public SurfaceAnimator.Animatable build() {
+            if (mPendingTransactionSupplier == null) {
+                throw new IllegalArgumentException("mPendingTransactionSupplier cannot be null");
+            }
+            if (mAnimationLeashFactory == null) {
+                throw new IllegalArgumentException("mAnimationLeashFactory cannot be null");
+            }
+            if (mCommitTransactionRunnable == null) {
+                throw new IllegalArgumentException("mCommitTransactionRunnable cannot be null");
+            }
+            if (mSurfaceControl == null) {
+                throw new IllegalArgumentException("mSurfaceControl cannot be null");
+            }
+            return new SimpleSurfaceAnimatable(this);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 1c015d0..9712277 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -398,9 +398,11 @@
             return;
         }
 
-        final Rect bounds = display.getBounds();
-        final int defaultWidth = bounds.width();
-        final int defaultHeight = bounds.height();
+        // Use stable frame instead of raw frame to avoid launching freeform windows on top of
+        // stable insets, which usually are system widgets such as sysbar & navbar.
+        final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable;
+        final int defaultWidth = displayStableBounds.width();
+        final int defaultHeight = displayStableBounds.height();
 
         int width;
         int height;
@@ -451,6 +453,7 @@
         }
 
         outBounds.set(0, 0, width, height);
+        outBounds.offset(displayStableBounds.left, displayStableBounds.top);
         final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
         final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
         outBounds.offset(xOffset, yOffset);
@@ -627,10 +630,14 @@
             @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
         // Default size, which is letterboxing/pillarboxing in display. That's to say the large
         // dimension of default size is the small dimension of display size, and the small dimension
-        // of default size is calculated to keep the same aspect ratio as the display's.
-        Rect displayBounds = display.getBounds();
-        final int portraitHeight = Math.min(displayBounds.width(), displayBounds.height());
-        final int otherDimension = Math.max(displayBounds.width(), displayBounds.height());
+        // of default size is calculated to keep the same aspect ratio as the display's. Here we use
+        // stable bounds of displays because that indicates the area that isn't occupied by system
+        // widgets (e.g. sysbar and navbar).
+        Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable;
+        final int portraitHeight =
+                Math.min(displayStableBounds.width(), displayStableBounds.height());
+        final int otherDimension =
+                Math.max(displayStableBounds.width(), displayStableBounds.height());
         final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
         final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
                 : portraitWidth;
@@ -656,16 +663,17 @@
         final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
 
         bounds.set(0, 0, width, height);
+        bounds.offset(displayStableBounds.left, displayStableBounds.top);
     }
 
     /**
      * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
-     * centers at its center or display's center if inOutBounds is empty.
+     * centers at its center or display's app bounds center if inOutBounds is empty.
      */
     private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
             @NonNull Rect inOutBounds) {
         if (inOutBounds.isEmpty()) {
-            display.getBounds(inOutBounds);
+            inOutBounds.set(display.mDisplayContent.mDisplayFrames.mStable);
         }
         final int left = inOutBounds.centerX() - width / 2;
         final int top = inOutBounds.centerY() - height / 2;
@@ -674,40 +682,40 @@
 
     private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
             @NonNull Rect inOutBounds) {
-        final Rect displayBounds = display.getBounds();
+        final Rect displayStableBounds = display.mDisplayContent.mDisplayFrames.mStable;
 
-        if (displayBounds.width() < inOutBounds.width()
-                || displayBounds.height() < inOutBounds.height()) {
+        if (displayStableBounds.width() < inOutBounds.width()
+                || displayStableBounds.height() < inOutBounds.height()) {
             // There is no way for us to fit the bounds in the display without changing width
             // or height. Just move the start to align with the display.
             final int layoutDirection =
                     mSupervisor.mRootActivityContainer.getConfiguration().getLayoutDirection();
             final int left = layoutDirection == View.LAYOUT_DIRECTION_RTL
-                    ? displayBounds.width() - inOutBounds.width()
-                    : 0;
-            inOutBounds.offsetTo(left, 0 /* newTop */);
+                    ? displayStableBounds.right - inOutBounds.right + inOutBounds.left
+                    : displayStableBounds.left;
+            inOutBounds.offsetTo(left, displayStableBounds.top);
             return;
         }
 
         final int dx;
-        if (inOutBounds.right > displayBounds.right) {
+        if (inOutBounds.right > displayStableBounds.right) {
             // Right edge is out of display.
-            dx = displayBounds.right - inOutBounds.right;
-        } else if (inOutBounds.left < displayBounds.left) {
+            dx = displayStableBounds.right - inOutBounds.right;
+        } else if (inOutBounds.left < displayStableBounds.left) {
             // Left edge is out of display.
-            dx = displayBounds.left - inOutBounds.left;
+            dx = displayStableBounds.left - inOutBounds.left;
         } else {
             // Vertical edges are all in display.
             dx = 0;
         }
 
         final int dy;
-        if (inOutBounds.top < displayBounds.top) {
+        if (inOutBounds.top < displayStableBounds.top) {
             // Top edge is out of display.
-            dy = displayBounds.top - inOutBounds.top;
-        } else if (inOutBounds.bottom > displayBounds.bottom) {
+            dy = displayStableBounds.top - inOutBounds.top;
+        } else if (inOutBounds.bottom > displayStableBounds.bottom) {
             // Bottom edge is out of display.
-            dy = displayBounds.bottom - inOutBounds.bottom;
+            dy = displayStableBounds.bottom - inOutBounds.bottom;
         } else {
             // Horizontal edges are all in display.
             dy = 0;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 42866f9..b680fa4 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -21,7 +21,7 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_FREEFORM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -50,9 +50,11 @@
 import android.view.InputEvent;
 import android.view.InputWindowHandle;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -296,13 +298,12 @@
         mDragWindowHandle.frameBottom = p.y;
 
         // Pause rotations before a drag.
-        if (DEBUG_ORIENTATION) {
-            Slog.d(TAG, "Pausing rotation during re-position");
-        }
+        ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
         mDisplayContent.getDisplayRotation().pause();
 
         // Notify InputMonitor to take mDragWindowHandle.
-        mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+        mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
+        new SurfaceControl.Transaction().syncInputWindows().apply(true);
 
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
@@ -338,9 +339,7 @@
         mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
 
         // Resume rotations after a drag.
-        if (DEBUG_ORIENTATION) {
-            Slog.d(TAG, "Resuming rotation after re-position");
-        }
+        ProtoLog.d(WM_DEBUG_ORIENTATION, "Resuming rotation after re-position");
         mDisplayContent.getDisplayRotation().resume();
         mDisplayContent = null;
         mClientCallback.unlinkToDeath(this, 0 /* flags */);
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index 2441954..56b3bba 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -24,7 +24,6 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -51,7 +50,6 @@
     private @Nullable TaskPositioner mTaskPositioner;
 
     private final Rect mTmpClipRect = new Rect();
-    private IBinder mTransferTouchFromToken;
 
     boolean isPositioningLocked() {
         return mTaskPositioner != null;
@@ -104,8 +102,6 @@
 
         mTmpClipRect.set(0, 0, p.x, p.y);
         t.setWindowCrop(mInputSurface, mTmpClipRect);
-        t.transferTouchFocus(mTransferTouchFromToken, h.token);
-        mTransferTouchFromToken = null;
     }
 
     boolean startMovingTask(IWindow window, float startX, float startY) {
@@ -168,6 +164,7 @@
         mPositioningDisplay = displayContent;
 
         mTaskPositioner = TaskPositioner.create(mService);
+        mTaskPositioner.register(displayContent);
 
         // We need to grab the touch focus so that the touch events during the
         // resizing/scrolling are not sent to the app. 'win' is the main window
@@ -178,8 +175,12 @@
                 && displayContent.mCurrentFocus.mAppToken == win.mAppToken) {
             transferFocusFromWin = displayContent.mCurrentFocus;
         }
-        mTransferTouchFromToken = transferFocusFromWin.mInputChannel.getToken();
-        mTaskPositioner.register(displayContent);
+        if (!mInputManager.transferTouchFocus(
+                transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
+            Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
+            cleanUpTaskPositioner();
+            return false;
+        }
 
         mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
         return true;
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
index d36ebf0..adecc36 100644
--- a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -15,14 +15,15 @@
  */
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 
 import android.graphics.GraphicBuffer;
-import android.util.Slog;
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.util.function.Function;
 
 /**
@@ -38,17 +39,16 @@
     private int mWidth;
     private int mHeight;
 
-    TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory, Task task,
-            SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) {
+    TaskScreenshotAnimatable(Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory,
+            Task task, SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer) {
         GraphicBuffer buffer = screenshotBuffer == null
                 ? null : screenshotBuffer.getGraphicBuffer();
         mTask = task;
         mWidth = (buffer != null) ? buffer.getWidth() : 1;
         mHeight = (buffer != null) ? buffer.getHeight() : 1;
-        if (DEBUG_RECENTS_ANIMATIONS) {
-            Slog.d(TAG, "Creating TaskScreenshotAnimatable: task: " + task
-                    + "width: " + mWidth + "height: " + mHeight);
-        }
+        ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
+                "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d",
+                        task, mWidth, mHeight);
         mSurfaceControl = surfaceControlFactory.apply(new SurfaceSession())
                 .setName("RecentTaskScreenshotSurface")
                 .setBufferSize(mWidth, mHeight)
@@ -58,6 +58,8 @@
             surface.copyFrom(mSurfaceControl);
             surface.attachAndQueueBufferWithColorSpace(buffer, screenshotBuffer.getColorSpace());
             surface.release();
+            final float scale = 1.0f * mTask.getBounds().width() / mWidth;
+            mSurfaceControl.setMatrix(scale, 0, 0, scale);
         }
         getPendingTransaction().show(mSurfaceControl);
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 7456f0d..d070850 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -42,7 +42,7 @@
 import static com.android.internal.policy.DecorView.getColorViewLeftInset;
 import static com.android.internal.policy.DecorView.getColorViewTopInset;
 import static com.android.internal.policy.DecorView.getNavigationBarRect;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
@@ -79,6 +79,7 @@
 import com.android.internal.policy.DecorView;
 import com.android.internal.view.BaseIWindow;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
+import com.android.server.protolog.common.ProtoLog;
 
 /**
  * This class represents a starting window that shows a snapshot.
@@ -259,14 +260,14 @@
             final long now = SystemClock.uptimeMillis();
             if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
                 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
-                if (DEBUG_STARTING_WINDOW) {
-                    Slog.v(TAG, "Defer removing snapshot surface in "  + (now - mShownTime) + "ms");
-                }
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
+                        "Defer removing snapshot surface in %dms", (now - mShownTime));
+
                 return;
             }
         }
         try {
-            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing snapshot surface");
             mSession.remove(mWindow);
         } catch (RemoteException e) {
             // Local call.
@@ -286,8 +287,8 @@
     private void drawSnapshot() {
         mSurface.copyFrom(mSurfaceControl);
 
-        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
-                + mSizeMismatch);
+        ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Drawing snapshot surface sizeMismatch=%b",
+                mSizeMismatch);
         if (mSizeMismatch) {
             // The dimensions of the buffer and the window don't match, so attaching the buffer
             // will fail. Better create a child window with the exact dimensions and fill the parent
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 895350b..513008d 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -16,17 +16,17 @@
 package com.android.server.wm;
 
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_REMOTE_ANIMATIONS;
 
 import android.graphics.Point;
 import android.os.SystemClock;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.function.Consumer;
@@ -68,15 +68,11 @@
         final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
         service.mRoot.forAllWallpaperWindows(wallpaperWindow -> {
             if (!wallpaperWindow.getDisplayContent().mWallpaperController.isWallpaperVisible()) {
-                if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) {
-                    Slog.d(TAG, "\tNot visible=" + wallpaperWindow);
-                }
+                ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tNot visible=%s", wallpaperWindow);
                 return;
             }
 
-            if (DEBUG_REMOTE_ANIMATIONS || DEBUG_RECENTS_ANIMATIONS) {
-                Slog.d(TAG, "\tvisible=" + wallpaperWindow);
-            }
+            ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tvisible=%s", wallpaperWindow);
             final WallpaperAnimationAdapter wallpaperAdapter = new WallpaperAnimationAdapter(
                     wallpaperWindow, durationHint, statusBarTransitionDelay,
                     animationCanceledRunnable);
@@ -129,7 +125,7 @@
     @Override
     public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
             SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "startAnimation");
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
 
         // Restore z-layering until client has a chance to modify it.
         t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex());
@@ -139,7 +135,7 @@
 
     @Override
     public void onAnimationCancelled(SurfaceControl animationLeash) {
-        if (DEBUG_REMOTE_ANIMATIONS) Slog.d(TAG, "onAnimationCancelled");
+        ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "onAnimationCancelled");
         mAnimationCanceledRunnable.accept(this);
     }
 
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 13902ee..e7b09db 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -24,7 +24,6 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -607,8 +606,9 @@
     boolean processWallpaperDrawPendingTimeout() {
         if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
             mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
-            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
-                    "*** WALLPAPER DRAW TIMEOUT");
+            if (DEBUG_WALLPAPER) {
+                Slog.v(TAG, "*** WALLPAPER DRAW TIMEOUT");
+            }
 
             // If there was a pending recents animation, start the animation anyways (it's better
             // to not see the wallpaper than for the animation to not start)
@@ -641,9 +641,11 @@
                                 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
 
                 }
-                if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
-                        "Wallpaper should be visible but has not been drawn yet. " +
-                                "mWallpaperDrawState=" + mWallpaperDrawState);
+                if (DEBUG_WALLPAPER) {
+                    Slog.v(TAG,
+                            "Wallpaper should be visible but has not been drawn yet. "
+                                    + "mWallpaperDrawState=" + mWallpaperDrawState);
+                }
                 break;
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c7916e8..f437b28 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -16,12 +16,11 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
 
 import android.content.Context;
 import android.os.Trace;
@@ -33,6 +32,7 @@
 
 import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -108,14 +108,6 @@
     }
 
     void removeDisplayLocked(final int displayId) {
-        final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
-        if (displayAnimator != null) {
-            if (displayAnimator.mScreenRotationAnimation != null) {
-                displayAnimator.mScreenRotationAnimation.kill();
-                displayAnimator.mScreenRotationAnimation = null;
-            }
-        }
-
         mDisplayContentsAnimators.delete(displayId);
     }
 
@@ -147,7 +139,7 @@
                 Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
             }
 
-            if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION animate");
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, ">>> OPEN TRANSACTION animate");
             mService.openSurfaceTransaction();
             try {
                 final AccessibilityController accessibilityController =
@@ -156,27 +148,6 @@
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
-                    DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
-
-                    final ScreenRotationAnimation screenRotationAnimation =
-                            displayAnimator.mScreenRotationAnimation;
-                    if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
-                        if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
-                            setAnimating(true);
-                        } else {
-                            mBulkUpdateParams |= SET_UPDATE_ROTATION;
-                            screenRotationAnimation.kill();
-                            displayAnimator.mScreenRotationAnimation = null;
-
-                            // display.
-                            if (accessibilityController != null) {
-                                // We just finished rotation animation which means we did not
-                                // announce the rotation and waited for it to end, announce now.
-                                accessibilityController.onRotationChangedLocked(dc);
-                            }
-                        }
-                    }
-
                     // Update animations of all applications, including those
                     // associated with exiting/removed apps
                     dc.updateWindowsForAnimator();
@@ -188,12 +159,6 @@
                     final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
 
                     dc.checkAppWindowsReadyToShow();
-
-                    final ScreenRotationAnimation screenRotationAnimation =
-                            mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
-                    if (screenRotationAnimation != null) {
-                        screenRotationAnimation.updateSurfaces(mTransaction);
-                    }
                     orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
                     if (accessibilityController != null) {
                         accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId);
@@ -213,7 +178,7 @@
                 Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
             } finally {
                 mService.closeSurfaceTransaction("WindowAnimator");
-                if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
+                ProtoLog.i(WM_SHOW_TRANSACTIONS, "<<< CLOSE TRANSACTION animate");
             }
 
             boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
@@ -273,22 +238,14 @@
 
     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
         final String subPrefix = "  " + prefix;
-        final String subSubPrefix = "  " + subPrefix;
 
         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
             pw.print(prefix); pw.print("DisplayContentsAnimator #");
                     pw.print(mDisplayContentsAnimators.keyAt(i));
                     pw.println(":");
-            final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
             final DisplayContent dc =
                     mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
             dc.dumpWindowAnimators(pw, subPrefix);
-            if (displayAnimator.mScreenRotationAnimation != null) {
-                pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
-                displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
-            } else if (dumpAll) {
-                pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
-            }
             pw.println();
         }
 
@@ -322,23 +279,6 @@
         return displayAnimator;
     }
 
-    void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
-        final DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
-
-        if (animator != null) {
-            animator.mScreenRotationAnimation = animation;
-        }
-    }
-
-    ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
-        if (displayId < 0) {
-            return null;
-        }
-
-        DisplayContentsAnimator animator = getDisplayContentsAnimatorLocked(displayId);
-        return animator != null? animator.mScreenRotationAnimation : null;
-    }
-
     void requestRemovalOfReplacedWindows(WindowState win) {
         mRemoveReplacedWindows = true;
     }
@@ -358,7 +298,6 @@
     }
 
     private class DisplayContentsAnimator {
-        ScreenRotationAnimation mScreenRotationAnimation = null;
     }
 
     boolean isAnimating() {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ec43ec5..264efe0 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -106,9 +106,6 @@
     private final Pools.SynchronizedPool<ForAllWindowsConsumerWrapper> mConsumerWrapperPool =
             new Pools.SynchronizedPool<>(3);
 
-    // The owner/creator for this container. No controller if null.
-    WindowContainerController mController;
-
     // The display this window container is on.
     protected DisplayContent mDisplayContent;
 
@@ -356,11 +353,6 @@
         if (mParent != null) {
             mParent.removeChild(this);
         }
-
-        if (mController != null) {
-            setController(null);
-        }
-
     }
 
     /**
@@ -1005,23 +997,6 @@
         } while (current != null);
     }
 
-    WindowContainerController getController() {
-        return mController;
-    }
-
-    void setController(WindowContainerController controller) {
-        if (mController != null && controller != null) {
-            throw new IllegalArgumentException("Can't set controller=" + mController
-                    + " for container=" + this + " Already set to=" + mController);
-        }
-        if (controller != null) {
-            controller.setContainer(this);
-        } else if (mController != null) {
-            mController.setContainer(null);
-        }
-        mController = controller;
-    }
-
     SurfaceControl.Builder makeSurface() {
         final WindowContainer p = getParent();
         return p.makeChildSurface(this);
diff --git a/services/core/java/com/android/server/wm/WindowContainerController.java b/services/core/java/com/android/server/wm/WindowContainerController.java
deleted file mode 100644
index 17bc0e2..0000000
--- a/services/core/java/com/android/server/wm/WindowContainerController.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.content.res.Configuration;
-
-/**
- * Class that allows the owner/creator of a {@link WindowContainer} to communicate directly with the
- * container and make changes.
- * Note that public calls (mostly in sub-classes) into this class are assumed to be originating from
- * outside the window manager so the window manager lock is held and appropriate permissions are
- * checked before calls are allowed to proceed.
- *
- * Test class: {@link WindowContainerControllerTests}
- */
-class WindowContainerController<E extends WindowContainer, I extends WindowContainerListener>
-        implements ConfigurationContainerListener {
-
-    final WindowManagerService mService;
-    final RootWindowContainer mRoot;
-    final WindowManagerGlobalLock mGlobalLock;
-
-    // The window container this controller owns.
-    E mContainer;
-    // Interface for communicating changes back to the owner.
-    final I mListener;
-
-    WindowContainerController(I listener, WindowManagerService service) {
-        mListener = listener;
-        mService = service;
-        mRoot = mService != null ? mService.mRoot : null;
-        mGlobalLock = mService != null ? mService.mGlobalLock : null;
-    }
-
-    void setContainer(E container) {
-        if (mContainer != null && container != null) {
-            throw new IllegalArgumentException("Can't set container=" + container
-                    + " for controller=" + this + " Already set to=" + mContainer);
-        }
-        mContainer = container;
-        if (mContainer != null && mListener != null) {
-            mListener.registerConfigurationChangeListener(this);
-        }
-    }
-
-    void removeContainer() {
-        // TODO: See if most uses cases should support removeIfPossible here.
-        //mContainer.removeIfPossible();
-        if (mContainer == null) {
-            return;
-        }
-
-        mContainer.setController(null);
-        mContainer = null;
-        if (mListener != null) {
-            mListener.unregisterConfigurationChangeListener(this);
-        }
-    }
-
-    @Override
-    public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        synchronized (mGlobalLock) {
-            if (mContainer == null) {
-                return;
-            }
-            mContainer.onRequestedOverrideConfigurationChanged(overrideConfiguration);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowContainerListener.java b/services/core/java/com/android/server/wm/WindowContainerListener.java
deleted file mode 100644
index 3d3d2e0..0000000
--- a/services/core/java/com/android/server/wm/WindowContainerListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.wm;
-
-import android.content.res.Configuration;
-
-/**
- * Interface used by the owner/creator of the container to listen to changes with the container.
- * @see WindowContainerController
- */
-public interface WindowContainerListener {
-    void registerConfigurationChangeListener(ConfigurationContainerListener listener);
-    void unregisterConfigurationChangeListener(ConfigurationContainerListener listener);
-    default void onInitializeOverrideConfiguration(Configuration config) {}
-}
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index c366e4d..93b0fd9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -33,32 +33,19 @@
     // Default log tag for the window manager package.
     static final String TAG_WM = "WindowManager";
 
-    static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG = false;
-    static final boolean DEBUG_ADD_REMOVE = false;
-    static final boolean DEBUG_FOCUS = false;
-    static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
     static final boolean DEBUG_ANIM = false;
-    static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_LAYERS = false;
     static final boolean DEBUG_INPUT = false;
     static final boolean DEBUG_INPUT_METHOD = false;
     static final boolean DEBUG_VISIBILITY = false;
-    static final boolean DEBUG_WINDOW_MOVEMENT = false;
-    static final boolean DEBUG_TOKEN_MOVEMENT = false;
-    static final boolean DEBUG_ORIENTATION = false;
-    static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
-    static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
-    static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
-    static final boolean DEBUG_SCREEN_ON = false;
     static final boolean DEBUG_SCREENSHOT = false;
-    static final boolean DEBUG_BOOT = false;
     static final boolean DEBUG_LAYOUT_REPEATS = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
     static final boolean DEBUG_TASK_MOVEMENT = false;
@@ -66,17 +53,9 @@
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
     static final boolean DEBUG_POWER = false;
-    static final boolean DEBUG_DIM_LAYER = false;
-    static final boolean SHOW_SURFACE_ALLOC = false;
-    static final boolean SHOW_TRANSACTIONS = false;
-    static final boolean SHOW_VERBOSE_TRANSACTIONS = false && SHOW_TRANSACTIONS;
-    static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
+    static final boolean SHOW_VERBOSE_TRANSACTIONS = false;
+    static final boolean SHOW_LIGHT_TRANSACTIONS = false;
     static final boolean SHOW_STACK_CRAWLS = false;
     static final boolean DEBUG_WINDOW_CROP = false;
     static final boolean DEBUG_UNKNOWN_APP_VISIBILITY = false;
-    static final boolean DEBUG_RECENTS_ANIMATIONS = false;
-    static final boolean DEBUG_REMOTE_ANIMATIONS = DEBUG_APP_TRANSITIONS || false;
-
-    static final String TAG_KEEP_SCREEN_ON = "DebugKeepScreenOn";
-    static final boolean DEBUG_KEEP_SCREEN_ON = false;
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index aa2a964..abbd1ab 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -161,9 +161,8 @@
         default boolean registerInputChannel(
                 DragState state, Display display, InputManagerService service,
                 InputChannel source) {
-            state.mTransferTouchFromToken = source.getToken();
             state.register(display);
-            return true;
+            return service.transferTouchFocus(source, state.getInputChannel());
         }
 
         /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b4309c7..1f45cfb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -81,27 +82,27 @@
 import static com.android.server.LockGuard.installLock;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_BOOT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.ProtoLogGroup.WM_ERROR;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerServiceDumpProto.DISPLAY_FROZEN;
@@ -267,6 +268,7 @@
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.power.ShutdownThread;
 import com.android.server.protolog.ProtoLogImpl;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.utils.PriorityDump;
 
 import java.io.BufferedWriter;
@@ -973,6 +975,7 @@
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
         }
     }
+
     /** Listener to notify activity manager about app transitions. */
     final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
             = new WindowManagerInternal.AppTransitionListener() {
@@ -989,7 +992,13 @@
             if (atoken == null) {
                 return;
             }
-            if (atoken.mLaunchTaskBehind) {
+
+            // While running a recents animation, this will get called early because we show the
+            // recents animation target activity immediately when the animation starts. Defer the
+            // mLaunchTaskBehind updates until recents animation finishes.
+            final boolean isRecentsAnimationTarget = getRecentsAnimationController() != null
+                    && getRecentsAnimationController().isTargetApp(atoken);
+            if (atoken.mLaunchTaskBehind && !isRecentsAnimationTarget) {
                 try {
                     mActivityTaskManager.notifyLaunchTaskBehindComplete(atoken.token);
                 } catch (RemoteException e) {
@@ -997,20 +1006,13 @@
                 atoken.mLaunchTaskBehind = false;
             } else {
                 atoken.updateReportedVisibilityLocked();
-                if (atoken.mEnteringAnimation) {
-                    if (getRecentsAnimationController() != null
-                            && getRecentsAnimationController().isTargetApp(atoken)) {
-                        // Currently running a recents animation, this will get called early because
-                        // we show the recents animation target activity immediately when the
-                        // animation starts. In this case, we should defer sending the finished
-                        // callback until the animation successfully finishes
-                        return;
-                    } else {
-                        atoken.mEnteringAnimation = false;
-                        try {
-                            mActivityTaskManager.notifyEnterAnimationComplete(atoken.token);
-                        } catch (RemoteException e) {
-                        }
+                // We should also defer sending the finished callback until the recents animation
+                // successfully finishes.
+                if (atoken.mEnteringAnimation && !isRecentsAnimationTarget) {
+                    atoken.mEnteringAnimation = false;
+                    try {
+                        mActivityTaskManager.notifyEnterAnimationComplete(atoken.token);
+                    } catch (RemoteException e) {
                     }
                 }
             }
@@ -1293,7 +1295,7 @@
             // The window manager only throws security exceptions, so let's
             // log all others.
             if (!(e instanceof SecurityException)) {
-                Slog.wtf(TAG_WM, "Window Manager Crash", e);
+                ProtoLog.wtf(WM_ERROR, "Window Manager Crash %s", e);
             }
             throw e;
         }
@@ -1333,38 +1335,41 @@
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
 
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
-                        + displayId + ".  Aborting.");
+                ProtoLog.w(WM_ERROR, "Attempted to add window to a display that does "
+                        + "not exist: %d. Aborting.", displayId);
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
             if (!displayContent.hasAccess(session.mUid)) {
-                Slog.w(TAG_WM, "Attempted to add window to a display for which the application "
-                        + "does not have access: " + displayId + ".  Aborting.");
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to add window to a display for which the application "
+                                + "does not have access: %d.  Aborting.", displayId);
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
 
             if (mWindowMap.containsKey(client.asBinder())) {
-                Slog.w(TAG_WM, "Window " + client + " is already added");
+                ProtoLog.w(WM_ERROR, "Window %s is already added", client);
                 return WindowManagerGlobal.ADD_DUPLICATE_ADD;
             }
 
             if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
                 parentWindow = windowForClientLocked(null, attrs.token, false);
                 if (parentWindow == null) {
-                    Slog.w(TAG_WM, "Attempted to add window with token that is not a window: "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add window with token that is not a window: "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                 }
                 if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                         && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
-                    Slog.w(TAG_WM, "Attempted to add window with token that is a sub-window: "
-                            + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add window with token that is a sub-window: "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
                 }
             }
 
             if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
-                Slog.w(TAG_WM, "Attempted to add private presentation window to a non-private display.  Aborting.");
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to add private presentation window to a non-private display.  "
+                                + "Aborting.");
                 return WindowManagerGlobal.ADD_PERMISSION_DENIED;
             }
 
@@ -1382,46 +1387,48 @@
 
             if (token == null) {
                 if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
-                    Slog.w(TAG_WM, "Attempted to add application window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add application window with unknown token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_INPUT_METHOD) {
-                    Slog.w(TAG_WM, "Attempted to add input method window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add input method window with unknown token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_VOICE_INTERACTION) {
-                    Slog.w(TAG_WM, "Attempted to add voice interaction window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR,
+                            "Attempted to add voice interaction window with unknown token "
+                                    + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_WALLPAPER) {
-                    Slog.w(TAG_WM, "Attempted to add wallpaper window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with unknown token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_DREAM) {
-                    Slog.w(TAG_WM, "Attempted to add Dream window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add Dream window with unknown token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_QS_DIALOG) {
-                    Slog.w(TAG_WM, "Attempted to add QS dialog window with unknown token "
-                          + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with unknown token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
-                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with unknown token "
-                            + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR,
+                            "Attempted to add Accessibility overlay window with unknown token "
+                                    + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
                 if (type == TYPE_TOAST) {
                     // Apps targeting SDK above N MR1 cannot arbitrary add toast windows.
                     if (doesAddToastWindowRequireToken(attrs.packageName, callingUid,
                             parentWindow)) {
-                        Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
-                                + attrs.token + ".  Aborting.");
+                        ProtoLog.w(WM_ERROR, "Attempted to add a toast window with unknown token "
+                                + "%s.  Aborting.", attrs.token);
                         return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                     }
                 }
@@ -1430,49 +1437,52 @@
                         (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
                 token = new WindowToken(this, binder, type, false, displayContent,
                         session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
-            } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
+            } else if (rootType >= FIRST_APPLICATION_WINDOW
+                    && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
                 if (atoken == null) {
-                    Slog.w(TAG_WM, "Attempted to add window with non-application token "
-                          + token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add window with non-application token "
+                            + ".%s Aborting.", token);
                     return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                 } else if (atoken.removed) {
-                    Slog.w(TAG_WM, "Attempted to add window with exiting application token "
-                          + token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add window with exiting application token "
+                            + ".%s Aborting.", token);
                     return WindowManagerGlobal.ADD_APP_EXITING;
                 } else if (type == TYPE_APPLICATION_STARTING && atoken.startingWindow != null) {
-                    Slog.w(TAG_WM, "Attempted to add starting window to token with already existing"
-                            + " starting window");
+                    ProtoLog.w(WM_ERROR,
+                            "Attempted to add starting window to token with already existing"
+                                    + " starting window");
                     return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                 }
             } else if (rootType == TYPE_INPUT_METHOD) {
                 if (token.windowType != TYPE_INPUT_METHOD) {
-                    Slog.w(TAG_WM, "Attempted to add input method window with bad token "
-                            + attrs.token + ".  Aborting.");
-                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    ProtoLog.w(WM_ERROR, "Attempted to add input method window with bad token "
+                            + "%s.  Aborting.", attrs.token);
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (rootType == TYPE_VOICE_INTERACTION) {
                 if (token.windowType != TYPE_VOICE_INTERACTION) {
-                    Slog.w(TAG_WM, "Attempted to add voice interaction window with bad token "
-                            + attrs.token + ".  Aborting.");
-                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    ProtoLog.w(WM_ERROR, "Attempted to add voice interaction window with bad token "
+                            + "%s.  Aborting.", attrs.token);
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (rootType == TYPE_WALLPAPER) {
                 if (token.windowType != TYPE_WALLPAPER) {
-                    Slog.w(TAG_WM, "Attempted to add wallpaper window with bad token "
-                            + attrs.token + ".  Aborting.");
-                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    ProtoLog.w(WM_ERROR, "Attempted to add wallpaper window with bad token "
+                            + "%s.  Aborting.", attrs.token);
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (rootType == TYPE_DREAM) {
                 if (token.windowType != TYPE_DREAM) {
-                    Slog.w(TAG_WM, "Attempted to add Dream window with bad token "
-                            + attrs.token + ".  Aborting.");
-                      return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                    ProtoLog.w(WM_ERROR, "Attempted to add Dream window with bad token "
+                            + "%s.  Aborting.", attrs.token);
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
                 if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
-                    Slog.w(TAG_WM, "Attempted to add Accessibility overlay window with bad token "
-                            + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR,
+                            "Attempted to add Accessibility overlay window with bad token "
+                                    + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (type == TYPE_TOAST) {
@@ -1480,18 +1490,19 @@
                 addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
                         callingUid, parentWindow);
                 if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
-                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
-                            + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add a toast window with bad token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (type == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
-                    Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "
-                            + attrs.token + ".  Aborting.");
+                    ProtoLog.w(WM_ERROR, "Attempted to add QS dialog window with bad token "
+                            + "%s.  Aborting.", attrs.token);
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
             } else if (token.asAppWindowToken() != null) {
-                Slog.w(TAG_WM, "Non-null appWindowToken for system window of rootType=" + rootType);
+                ProtoLog.w(WM_ERROR, "Non-null appWindowToken for system window of rootType=%d",
+                        rootType);
                 // It is not valid to use an app token with other system types; we will
                 // instead make a new token for it (as if null had been passed in for the token).
                 attrs.token = null;
@@ -1505,13 +1516,13 @@
             if (win.mDeathRecipient == null) {
                 // Client has apparently died, so there is no reason to
                 // continue.
-                Slog.w(TAG_WM, "Adding window client " + client.asBinder()
-                        + " that is dead, aborting.");
+                ProtoLog.w(WM_ERROR, "Adding window client %s"
+                        + " that is dead, aborting.", client.asBinder());
                 return WindowManagerGlobal.ADD_APP_EXITING;
             }
 
             if (win.getDisplayContent() == null) {
-                Slog.w(TAG_WM, "Adding window to Display that has been removed.");
+                ProtoLog.w(WM_ERROR, "Adding window to Display that has been removed.");
                 return WindowManagerGlobal.ADD_INVALID_DISPLAY;
             }
 
@@ -1543,7 +1554,7 @@
             // schedule hiding all of its toast windows.
             if (type == TYPE_TOAST) {
                 if (!displayContent.canAddToastWindowForUid(callingUid)) {
-                    Slog.w(TAG_WM, "Adding more than one toast window for UID at a time.");
+                    ProtoLog.w(WM_ERROR, "Adding more than one toast window for UID at a time.");
                     return WindowManagerGlobal.ADD_DUPLICATE_ADD;
                 }
                 // Make sure this happens before we moved focus as one can make the
@@ -1589,8 +1600,8 @@
             final AppWindowToken aToken = token.asAppWindowToken();
             if (type == TYPE_APPLICATION_STARTING && aToken != null) {
                 aToken.startingWindow = win;
-                if (DEBUG_STARTING_WINDOW) Slog.v (TAG_WM, "addWindow: " + aToken
-                        + " startingWindow=" + win);
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "addWindow: %s startingWindow=%s",
+                        aToken, win);
             }
 
             boolean imMayMove = true;
@@ -1607,7 +1618,7 @@
                 if (type == TYPE_WALLPAPER) {
                     displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                     displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
-                } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
+                } else if ((attrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                     displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
                 } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
                     // If there is currently a wallpaper being shown, and
@@ -1692,10 +1703,9 @@
             }
             displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
 
-            if (DEBUG || DEBUG_ADD_REMOVE) {
-                Slog.v(TAG_WM, "addWindow: New client " + client.asBinder()
-                        + ": window=" + win + " Callers=" + Debug.getCallers(5));
-            }
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
+                    + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
+
 
             if (win.isVisibleOrAdding() && displayContent.updateOrientation()) {
                 displayContent.sendNewConfiguration();
@@ -1858,7 +1868,7 @@
      * forgetting to add the wiring when a new parent of WindowState is added.
      */
     void postWindowRemoveCleanupLocked(WindowState win) {
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win);
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "postWindowRemoveCleanupLocked: %s", win);
         mWindowMap.remove(win.mClient.asBinder());
 
         final DisplayContent dc = win.getDisplayContent();
@@ -1873,7 +1883,7 @@
         mResizingWindows.remove(win);
         updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
         mWindowsChanged = true;
-        if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Final remove of window: " + win);
+        ProtoLog.v(WM_DEBUG_WINDOW_MOVEMENT, "Final remove of window: %s", win);
 
         final DisplayContent displayContent = win.getDisplayContent();
         if (displayContent.mInputMethodWindow == win) {
@@ -1882,7 +1892,7 @@
 
         final WindowToken token = win.mToken;
         final AppWindowToken atoken = win.mAppToken;
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Removing " + win + " from " + token);
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Removing %s from %s", win, token);
         // Window will already be removed from token before this post clean-up method is called.
         if (token.isEmpty()) {
             if (!token.mPersistOnEmpty) {
@@ -1942,11 +1952,6 @@
         }
     }
 
-    static void logSurface(SurfaceControl s, String title, String msg) {
-        String str = "  SURFACE " + s + ": " + msg + " / " + title;
-        Slog.i(TAG_WM, str);
-    }
-
     static void logWithStack(String tag, String s) {
         RuntimeException e = null;
         if (SHOW_STACK_CRAWLS) {
@@ -1961,8 +1966,8 @@
         try {
             synchronized (mGlobalLock) {
                 WindowState w = windowForClientLocked(session, client, false);
-                if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
-                        "transparentRegionHint=" + region, false);
+                ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE transparentRegionHint=%s: %s",
+                        region, w);
 
                 if ((w != null) && w.mHasSurface) {
                     w.mWinAnimator.setTransparentRegionHintLocked(region);
@@ -2186,12 +2191,10 @@
             win.mInRelayout = true;
 
             win.mViewVisibility = viewVisibility;
-            if (DEBUG_SCREEN_ON) {
-                RuntimeException stack = new RuntimeException();
-                stack.fillInStackTrace();
-                Slog.i(TAG_WM, "Relayout " + win + ": oldVis=" + oldVisibility
-                        + " newVis=" + viewVisibility, stack);
-            }
+            ProtoLog.i(WM_DEBUG_SCREEN_ON,
+                    "Relayout %s: oldVis=%d newVis=%d. %s", win, oldVisibility,
+                            viewVisibility, new RuntimeException().fillInStackTrace());
+
 
             win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags & WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
@@ -2236,9 +2239,9 @@
                 } catch (Exception e) {
                     displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
 
-                    Slog.w(TAG_WM, "Exception thrown when creating surface for client "
-                             + client + " (" + win.mAttrs.getTitle() + ")",
-                             e);
+                    ProtoLog.w(WM_ERROR,
+                            "Exception thrown when creating surface for client %s (%s). %s",
+                            client, win.mAttrs.getTitle(), e);
                     Binder.restoreCallingIdentity(origId);
                     return 0;
                 }
@@ -2362,21 +2365,21 @@
             outInsetsState.set(displayContent.getInsetsStateController().getInsetsForDispatch(win));
             if (DEBUG) {
                 Slog.v(TAG_WM, "Relayout given client " + client.asBinder()
-                                + ", requestedWidth=" + requestedWidth
-                                + ", requestedHeight=" + requestedHeight
-                                + ", viewVisibility=" + viewVisibility
-                                + "\nRelayout returning frame=" + outFrame
-                                + ", surface=" + outSurfaceControl);
+                        + ", requestedWidth=" + requestedWidth
+                        + ", requestedHeight=" + requestedHeight
+                        + ", viewVisibility=" + viewVisibility
+                        + "\nRelayout returning frame=" + outFrame
+                        + ", surface=" + outSurfaceControl);
             }
 
-            if (DEBUG || DEBUG_FOCUS) {
-                Slog.v(TAG_WM, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
-            }
+            ProtoLog.v(WM_DEBUG_FOCUS, "Relayout of %s: focusMayChange=%b",
+                    win, focusMayChange);
 
             result |= mInTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0;
 
             if (DEBUG_LAYOUT) {
-                Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
+                Slog.v(TAG_WM,
+                        "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
             }
             win.mInRelayout = false;
 
@@ -2454,11 +2457,12 @@
         }
         if (surfaceController != null) {
             surfaceController.getSurfaceControl(outSurfaceControl);
-            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurfaceControl + ": copied");
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "OUT SURFACE %s: copied", outSurfaceControl);
+
         } else {
             // For some reason there isn't a surface.  Clear the
             // caller's object so they see the same state.
-            Slog.w(TAG_WM, "Failed to create surface control for " + win);
+            ProtoLog.w(WM_ERROR, "Failed to create surface control for %s", win);
             outSurfaceControl.release();
         }
 
@@ -2487,8 +2491,8 @@
         try {
             synchronized (mGlobalLock) {
                 WindowState win = windowForClientLocked(session, client, false);
-                if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "finishDrawingWindow: " + win + " mDrawState="
-                        + (win != null ? win.mWinAnimator.drawStateToString() : "null"));
+                ProtoLog.d(WM_DEBUG_ADD_REMOVE, "finishDrawingWindow: %s mDrawState=%s",
+                        win, (win != null ? win.mWinAnimator.drawStateToString() : "null"));
                 if (win != null && win.mWinAnimator.finishDrawingLocked(postDrawTransaction)) {
                     if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                         win.getDisplayContent().pendingLayoutChanges |=
@@ -2513,9 +2517,8 @@
                 == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
-        final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
-                + ", uid=" + Binder.getCallingUid() + " requires " + permission;
-        Slog.w(TAG_WM, msg);
+        ProtoLog.w(WM_ERROR, "Permission Denial: %s from pid=%d, uid=%d requires %s",
+                func, Binder.getCallingPid(), Binder.getCallingUid(), permission);
         return false;
     }
 
@@ -2528,16 +2531,16 @@
         synchronized (mGlobalLock) {
             final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
             if (dc == null) {
-                Slog.w(TAG_WM, "addWindowToken: Attempted to add token: " + binder
-                        + " for non-exiting displayId=" + displayId);
+                ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s"
+                        + " for non-exiting displayId=%d", binder, displayId);
                 return;
             }
 
             WindowToken token = dc.getWindowToken(binder);
             if (token != null) {
-                Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder
-                        + " for already created window token: " + token
-                        + " displayId=" + displayId);
+                ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s"
+                        + " for already created window token: %s"
+                        + " displayId=%d", binder, token, displayId);
                 return;
             }
             if (type == TYPE_WALLPAPER) {
@@ -2560,15 +2563,16 @@
             synchronized (mGlobalLock) {
                 final DisplayContent dc = mRoot.getDisplayContent(displayId);
                 if (dc == null) {
-                    Slog.w(TAG_WM, "removeWindowToken: Attempted to remove token: " + binder
-                            + " for non-exiting displayId=" + displayId);
+                    ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+                            + " for non-exiting displayId=%d", binder, displayId);
                     return;
                 }
 
                 final WindowToken token = dc.removeWindowToken(binder);
                 if (token == null) {
-                    Slog.w(TAG_WM,
-                            "removeWindowToken: Attempted to remove non-existing token: " + binder);
+                    ProtoLog.w(WM_ERROR,
+                            "removeWindowToken: Attempted to remove non-existing token: %s",
+                            binder);
                     return;
                 }
 
@@ -3208,14 +3212,11 @@
 
     public void enableScreenAfterBoot() {
         synchronized (mGlobalLock) {
-            if (DEBUG_BOOT) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.i(TAG_WM, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
-                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
-                        + " mShowingBootMessages=" + mShowingBootMessages
-                        + " mSystemBooted=" + mSystemBooted, here);
-            }
+            ProtoLog.i(WM_DEBUG_BOOT, "enableScreenAfterBoot: mDisplayEnabled=%b "
+                            + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
+                            + "%s",
+                    mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
+                    new RuntimeException("here").fillInStackTrace());
             if (mSystemBooted) {
                 return;
             }
@@ -3239,14 +3240,11 @@
     }
 
     void enableScreenIfNeededLocked() {
-        if (DEBUG_BOOT) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.i(TAG_WM, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
-                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
-                    + " mShowingBootMessages=" + mShowingBootMessages
-                    + " mSystemBooted=" + mSystemBooted, here);
-        }
+        ProtoLog.i(WM_DEBUG_BOOT, "enableScreenIfNeededLocked: mDisplayEnabled=%b "
+                        + "mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. "
+                        + "%s",
+                mDisplayEnabled, mForceDisplayEnabled, mShowingBootMessages, mSystemBooted,
+                new RuntimeException("here").fillInStackTrace());
         if (mDisplayEnabled) {
             return;
         }
@@ -3261,7 +3259,7 @@
             if (mDisplayEnabled) {
                 return;
             }
-            Slog.w(TAG_WM, "***** BOOT TIMEOUT: forcing display enabled");
+            ProtoLog.w(WM_ERROR, "***** BOOT TIMEOUT: forcing display enabled");
             mForceDisplayEnabled = true;
         }
         performEnableScreen();
@@ -3276,11 +3274,10 @@
 
     private void performEnableScreen() {
         synchronized (mGlobalLock) {
-            if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
-                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
-                    + " mShowingBootMessages=" + mShowingBootMessages
-                    + " mSystemBooted=" + mSystemBooted
-                    + " mOnlyCore=" + mOnlyCore,
+            ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: mDisplayEnabled=%b"
+                            + " mForceDisplayEnabled=%b" + " mShowingBootMessages=%b"
+                            + " mSystemBooted=%b mOnlyCore=%b. %s", mDisplayEnabled,
+                    mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, mOnlyCore,
                     new RuntimeException("here").fillInStackTrace());
             if (mDisplayEnabled) {
                 return;
@@ -3294,10 +3291,12 @@
             }
 
             // Don't enable the screen until all existing windows have been drawn.
-            if (!mForceDisplayEnabled
-                    // TODO(multidisplay): Expand to all displays?
-                    && getDefaultDisplayContentLocked().checkWaitingForWindows()) {
-                return;
+            if (!mForceDisplayEnabled) {
+                for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {
+                    if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) {
+                        return;
+                    }
+                }
             }
 
             if (!mBootAnimationStopped) {
@@ -3310,14 +3309,14 @@
             }
 
             if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
-                if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
+                ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete");
                 return;
             }
 
             try {
                 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                 if (surfaceFlinger != null) {
-                    Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
+                    ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                     Parcel data = Parcel.obtain();
                     data.writeInterfaceToken("android.ui.ISurfaceComposer");
                     surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
@@ -3325,13 +3324,13 @@
                     data.recycle();
                 }
             } catch (RemoteException ex) {
-                Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
+                ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
             }
 
             EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
             Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
             mDisplayEnabled = true;
-            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM, "******************** ENABLING SCREEN!");
+            ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");
 
             // Enable input dispatch.
             mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);
@@ -3353,24 +3352,21 @@
             mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);
             mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,
                     BOOT_ANIMATION_POLL_INTERVAL);
-            if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Waiting for anim complete");
+            ProtoLog.i(WM_DEBUG_BOOT, "checkBootAnimationComplete: Waiting for anim complete");
             return false;
         }
-        if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Animation complete!");
+        ProtoLog.i(WM_DEBUG_BOOT, "checkBootAnimationComplete: Animation complete!");
         return true;
     }
 
     public void showBootMessage(final CharSequence msg, final boolean always) {
         boolean first = false;
         synchronized (mGlobalLock) {
-            if (DEBUG_BOOT) {
-                RuntimeException here = new RuntimeException("here");
-                here.fillInStackTrace();
-                Slog.i(TAG_WM, "showBootMessage: msg=" + msg + " always=" + always
-                        + " mAllowBootMessages=" + mAllowBootMessages
-                        + " mShowingBootMessages=" + mShowingBootMessages
-                        + " mSystemBooted=" + mSystemBooted, here);
-            }
+            ProtoLog.i(WM_DEBUG_BOOT, "showBootMessage: msg=%s always=%b"
+                            + " mAllowBootMessages=%b mShowingBootMessages=%b"
+                            + " mSystemBooted=%b. %s", msg, always, mAllowBootMessages,
+                    mShowingBootMessages, mSystemBooted,
+                    new RuntimeException("here").fillInStackTrace());
             if (!mAllowBootMessages) {
                 return;
             }
@@ -3392,14 +3388,11 @@
     }
 
     public void hideBootMessagesLocked() {
-        if (DEBUG_BOOT) {
-            RuntimeException here = new RuntimeException("here");
-            here.fillInStackTrace();
-            Slog.i(TAG_WM, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
-                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
-                    + " mShowingBootMessages=" + mShowingBootMessages
-                    + " mSystemBooted=" + mSystemBooted, here);
-        }
+        ProtoLog.i(WM_DEBUG_BOOT, "hideBootMessagesLocked: mDisplayEnabled=%b"
+                        + " mForceDisplayEnabled=%b mShowingBootMessages=%b"
+                        + " mSystemBooted=%b. %s", mDisplayEnabled, mForceDisplayEnabled,
+                mShowingBootMessages, mSystemBooted,
+                new RuntimeException("here").fillInStackTrace());
         if (mShowingBootMessages) {
             mShowingBootMessages = false;
             mPolicy.hideBootMessages();
@@ -3691,8 +3684,7 @@
             throw new SecurityException("Requires SET_ORIENTATION permission");
         }
 
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "thawRotation: mRotation="
-                + getDefaultDisplayRotation());
+        ProtoLog.v(WM_DEBUG_ORIENTATION, "thawRotation: mRotation=%d", getDefaultDisplayRotation());
 
         long origId = Binder.clearCallingIdentity();
         try {
@@ -3741,9 +3733,9 @@
     }
 
     private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
-        if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:"
-                + " alwaysSendConfiguration=" + alwaysSendConfiguration
-                + " forceRelayout=" + forceRelayout);
+        ProtoLog.v(WM_DEBUG_ORIENTATION, "updateRotationUnchecked:"
+                        + " alwaysSendConfiguration=%b forceRelayout=%b",
+                alwaysSendConfiguration, forceRelayout);
 
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");
 
@@ -3992,7 +3984,7 @@
                 try {
                     return mViewServer.start();
                 } catch (IOException e) {
-                    Slog.w(TAG_WM, "View server did not start");
+                    ProtoLog.w(WM_ERROR, "View server did not start");
                 }
             }
             return false;
@@ -4002,7 +3994,7 @@
             mViewServer = new ViewServer(this, port);
             return mViewServer.start();
         } catch (IOException e) {
-            Slog.w(TAG_WM, "View server did not start");
+            ProtoLog.w(WM_ERROR, "View server did not start");
         }
         return false;
     }
@@ -4232,7 +4224,8 @@
             }
 
         } catch (Exception e) {
-            Slog.w(TAG_WM, "Could not send command " + command + " with parameters " + parameters, e);
+            ProtoLog.w(WM_ERROR, "Could not send command %s with parameters %s. %s", command,
+                    parameters, e);
             success = false;
         } finally {
             if (data != null) {
@@ -4381,9 +4374,9 @@
     public boolean detectSafeMode() {
         if (!mInputManagerCallback.waitForInputDevicesReady(
                 INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
-            Slog.w(TAG_WM, "Devices still not ready after waiting "
-                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
-                   + " milliseconds before attempting to detect safe mode.");
+            ProtoLog.w(WM_ERROR, "Devices still not ready after waiting %d"
+                            + " milliseconds before attempting to detect safe mode.",
+                    INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS);
         }
 
         if (Settings.Global.getInt(
@@ -4411,14 +4404,14 @@
         } catch (IllegalArgumentException e) {
         }
         if (mSafeMode) {
-            Log.i(TAG_WM, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
-                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
+            ProtoLog.i(WM_ERROR, "SAFE MODE ENABLED (menu=%d s=%d dpad=%d"
+                    + " trackball=%d)", menuState, sState, dpadState, trackballState);
             // May already be set if (for instance) this process has crashed
             if (SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) == 0) {
                 SystemProperties.set(ShutdownThread.RO_SAFEMODE_PROPERTY, "1");
             }
         } else {
-            Log.i(TAG_WM, "SAFE MODE not enabled");
+            ProtoLog.i(WM_ERROR, "SAFE MODE not enabled");
         }
         mPolicy.setSafeMode(mSafeMode);
         return mSafeMode;
@@ -4577,10 +4570,11 @@
                             return;
                         }
                         displayContent.mLastFocus = newFocus;
-                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Focus moving from " + lastFocus +
-                                " to " + newFocus + " displayId=" + displayContent.getDisplayId());
+                        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Focus moving from %s"
+                                        + " to %s displayId=%d", lastFocus, newFocus,
+                                displayContent.getDisplayId());
                         if (newFocus != null && lastFocus != null && !newFocus.isDisplayedLw()) {
-                            if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Delaying loss of focus...");
+                            ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Delaying loss of focus...");
                             displayContent.mLosingFocus.add(lastFocus);
                             lastFocus = null;
                         }
@@ -4594,13 +4588,13 @@
                     }
 
                     if (newFocus != null) {
-                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus);
+                        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Gaining focus: %s", newFocus);
                         newFocus.reportFocusChangedSerialized(true, mInTouchMode);
                         notifyFocusChanged();
                     }
 
                     if (lastFocus != null) {
-                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus);
+                        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing focus: %s", lastFocus);
                         lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
                     }
                     break;
@@ -4617,7 +4611,7 @@
 
                     final int N = losers.size();
                     for (int i = 0; i < N; i++) {
-                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing delayed focus: " +
+                        ProtoLog.i(WM_DEBUG_FOCUS_LIGHT, "Losing delayed focus: %s",
                                 losers.get(i));
                         losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
                     }
@@ -4700,9 +4694,9 @@
 
                 case APP_FREEZE_TIMEOUT: {
                     synchronized (mGlobalLock) {
-                        Slog.w(TAG_WM, "App freeze timeout expired.");
+                        ProtoLog.w(WM_ERROR, "App freeze timeout expired.");
                         mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
-                        for (int i = mAppFreezeListeners.size() - 1; i >=0 ; --i) {
+                        for (int i = mAppFreezeListeners.size() - 1; i >= 0; --i) {
                             mAppFreezeListeners.get(i).onAppFreezeTimeout();
                         }
                     }
@@ -4743,7 +4737,8 @@
                 case WAITING_FOR_DRAWN_TIMEOUT: {
                     Runnable callback = null;
                     synchronized (mGlobalLock) {
-                        Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
+                        ProtoLog.w(WM_ERROR, "Timeout waiting for drawn: undrawn=%s",
+                                mWaitingForDrawn);
                         mWaitingForDrawn.clear();
                         callback = mWaitingForDrawnCallback;
                         mWaitingForDrawnCallback = null;
@@ -4817,7 +4812,7 @@
                 case CHECK_IF_BOOT_ANIMATION_FINISHED: {
                     final boolean bootAnimationComplete;
                     synchronized (mGlobalLock) {
-                        if (DEBUG_BOOT) Slog.i(TAG_WM, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
+                        ProtoLog.i(WM_DEBUG_BOOT, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
                         bootAnimationComplete = checkBootAnimationCompleteLocked();
                     }
                     if (bootAnimationComplete) {
@@ -5031,10 +5026,10 @@
                 int width, height;
                 try {
                     width = Integer.parseInt(sizeStr.substring(0, pos));
-                    height = Integer.parseInt(sizeStr.substring(pos+1));
+                    height = Integer.parseInt(sizeStr.substring(pos + 1));
                     if (displayContent.mBaseDisplayWidth != width
                             || displayContent.mBaseDisplayHeight != height) {
-                        Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
+                        ProtoLog.i(WM_ERROR, "FORCED DISPLAY SIZE: %dx%d", width, height);
                         displayContent.updateBaseDisplayMetrics(width, height,
                                 displayContent.mBaseDisplayDensity);
                         changed = true;
@@ -5055,7 +5050,7 @@
         int mode = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DISPLAY_SCALING_FORCE, 0);
         if (displayContent.mDisplayScalingDisabled != (mode != 0)) {
-            Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED");
+            ProtoLog.i(WM_ERROR, "FORCED DISPLAY SCALING DISABLED");
             displayContent.mDisplayScalingDisabled = true;
             changed = true;
         }
@@ -5235,7 +5230,7 @@
                 throw new IllegalArgumentException(
                         "Requested window " + client + " does not exist");
             }
-            Slog.w(TAG_WM, "Failed looking up window callers=" + Debug.getCallers(3));
+            ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
             return null;
         }
         if (session != null && win.mSession != session) {
@@ -5243,7 +5238,7 @@
                 throw new IllegalArgumentException("Requested window " + client + " is in session "
                         + win.mSession + ", not " + session);
             }
-            Slog.w(TAG_WM, "Failed looking up window callers=" + Debug.getCallers(3));
+            ProtoLog.w(WM_ERROR, "Failed looking up window callers=%s", Debug.getCallers(3));
             return null;
         }
 
@@ -5255,7 +5250,7 @@
         // it frozen/off until this window draws at its new
         // orientation.
         if (!w.mToken.okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
+            ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w);
             w.setOrientationChanging(true);
             w.mLastFreezeDuration = 0;
             mRoot.mOrientationChangeComplete = false;
@@ -5275,22 +5270,22 @@
         }
         for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
             WindowState win = mWaitingForDrawn.get(j);
-            if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win +
-                    ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
-                    " mHasSurface=" + win.mHasSurface +
-                    " drawState=" + win.mWinAnimator.mDrawState);
+            ProtoLog.i(WM_DEBUG_SCREEN_ON,
+                        "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
+                        win, win.mRemoved, win.isVisibleLw(), win.mHasSurface,
+                        win.mWinAnimator.mDrawState);
             if (win.mRemoved || !win.mHasSurface || !win.isVisibleByPolicy()) {
                 // Window has been removed or hidden; no draw will now happen, so stop waiting.
-                if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
+                ProtoLog.w(WM_DEBUG_SCREEN_ON, "Aborted waiting for drawn: %s", win);
                 mWaitingForDrawn.remove(win);
             } else if (win.hasDrawnLw()) {
                 // Window is now drawn (and shown).
-                if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win);
+                ProtoLog.d(WM_DEBUG_SCREEN_ON, "Window drawn win=%s", win);
                 mWaitingForDrawn.remove(win);
             }
         }
         if (mWaitingForDrawn.isEmpty()) {
-            if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!");
+            ProtoLog.d(WM_DEBUG_SCREEN_ON, "All windows drawn!");
             mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
             mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
         }
@@ -5307,19 +5302,15 @@
         final boolean state = mHoldingScreenWakeLock.isHeld();
         if (hold != state) {
             if (hold) {
-                if (DEBUG_KEEP_SCREEN_ON) {
-                    Slog.d(TAG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to "
-                            + mRoot.mHoldScreenWindow);
-                }
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to %s",
+                            mRoot.mHoldScreenWindow);
                 mLastWakeLockHoldingWindow = mRoot.mHoldScreenWindow;
                 mLastWakeLockObscuringWindow = null;
                 mHoldingScreenWakeLock.acquire();
                 mPolicy.keepScreenOnStartedLw();
             } else {
-                if (DEBUG_KEEP_SCREEN_ON) {
-                    Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by "
-                            + mRoot.mObscuringWindow);
-                }
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by %s",
+                            mRoot.mObscuringWindow);
                 mLastWakeLockHoldingWindow = null;
                 mLastWakeLockObscuringWindow = mRoot.mObscuringWindow;
                 mPolicy.keepScreenOnStoppedLw();
@@ -5363,10 +5354,9 @@
             return;
         }
 
-        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
-                "startFreezingDisplayLocked: exitAnim="
-                + exitAnim + " enterAnim=" + enterAnim
-                + " called by " + Debug.getCallers(8));
+        ProtoLog.d(WM_DEBUG_ORIENTATION,
+                            "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
+                            exitAnim, enterAnim, Debug.getCallers(8));
         mScreenFrozenLock.acquire();
 
         mDisplayFrozen = true;
@@ -5392,7 +5382,7 @@
         mExitAnimId = exitAnim;
         mEnterAnimId = enterAnim;
         ScreenRotationAnimation screenRotationAnimation =
-                mAnimator.getScreenRotationAnimationLocked(mFrozenDisplayId);
+                displayContent.getRotationAnimation();
         if (screenRotationAnimation != null) {
             screenRotationAnimation.kill();
         }
@@ -5404,8 +5394,7 @@
         screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
                 displayContent.getDisplayRotation().isFixedToUserRotation(), isSecure,
                 this);
-        mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId,
-                screenRotationAnimation);
+        displayContent.setRotationAnimation(screenRotationAnimation);
     }
 
     void stopFreezingDisplayLocked() {
@@ -5419,17 +5408,17 @@
         if (waitingForConfig || mAppsFreezingScreen > 0
                 || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
                 || mClientFreezingScreen || numOpeningApps > 0) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
-                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + waitingForConfig
-                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
-                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
-                + ", mClientFreezingScreen=" + mClientFreezingScreen
-                + ", mOpeningApps.size()=" + numOpeningApps);
+            ProtoLog.d(WM_DEBUG_ORIENTATION,
+                                "stopFreezingDisplayLocked: Returning mWaitingForConfig=%b, "
+                                        + "mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, "
+                                        + "mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+                                waitingForConfig, mAppsFreezingScreen, mWindowsFreezingScreen,
+                                mClientFreezingScreen, numOpeningApps);
             return;
         }
 
-        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
-                "stopFreezingDisplayLocked: Unfreezing now");
+        ProtoLog.d(WM_DEBUG_ORIENTATION,
+                    "stopFreezingDisplayLocked: Unfreezing now");
 
 
         // We must make a local copy of the displayId as it can be potentially overwritten later on
@@ -5447,7 +5436,7 @@
             sb.append(" due to ");
             sb.append(mLastFinishedFreezeSource);
         }
-        Slog.i(TAG_WM, sb.toString());
+        ProtoLog.i(WM_ERROR, "%s", sb.toString());
         mH.removeMessages(H.APP_FREEZE_TIMEOUT);
         mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
         if (PROFILE_ORIENTATION) {
@@ -5456,10 +5445,10 @@
 
         boolean updateRotation = false;
 
-        ScreenRotationAnimation screenRotationAnimation =
-                mAnimator.getScreenRotationAnimationLocked(displayId);
+        ScreenRotationAnimation screenRotationAnimation = displayContent == null ? null
+                : displayContent.getRotationAnimation();
         if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
-            if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
+            ProtoLog.i(WM_DEBUG_ORIENTATION, "**** Dismissing screen rotation animation");
             DisplayInfo displayInfo = displayContent.getDisplayInfo();
             // Get rotation animation again, with new top window
             if (!displayContent.getDisplayRotation().validateRotationAnimation(
@@ -5470,16 +5459,15 @@
                     getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
                         displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
                 mTransaction.apply();
-                scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
-                mAnimator.setScreenRotationAnimationLocked(displayId, null);
+                displayContent.setRotationAnimation(null);
                 updateRotation = true;
             }
         } else {
             if (screenRotationAnimation != null) {
                 screenRotationAnimation.kill();
-                mAnimator.setScreenRotationAnimationLocked(displayId, null);
+                displayContent.setRotationAnimation(null);
             }
             updateRotation = true;
         }
@@ -5503,7 +5491,7 @@
         mScreenFrozenLock.release();
 
         if (updateRotation && displayContent != null) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
+            ProtoLog.d(WM_DEBUG_ORIENTATION, "Performing post-rotate rotation");
             configChanged |= displayContent.updateRotationUnchecked();
         }
 
@@ -6316,17 +6304,20 @@
     /**
      * Hint to a token that its activity will relaunch, which will trigger removal and addition of
      * a window.
+     *
      * @param token Application token for which the activity will be relaunched.
      */
     void setWillReplaceWindow(IBinder token, boolean animate) {
         final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
         if (appWindowToken == null) {
-            Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+            ProtoLog.w(WM_ERROR, "Attempted to set replacing window on non-existing app token %s",
+                    token);
             return;
         }
         if (!appWindowToken.hasContentToDisplay()) {
-            Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content"
-                    + token);
+            ProtoLog.w(WM_ERROR,
+                    "Attempted to set replacing window on app token with no content %s",
+                    token);
             return;
         }
         appWindowToken.setWillReplaceWindows(animate);
@@ -6348,13 +6339,15 @@
         synchronized (mGlobalLock) {
             final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
             if (appWindowToken == null) {
-                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
-                        + token);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to set replacing window on non-existing app token %s",
+                        token);
                 return;
             }
             if (!appWindowToken.hasContentToDisplay()) {
-                Slog.w(TAG_WM, "Attempted to set replacing window on app token with no content"
-                        + token);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to set replacing window on app token with no content %s",
+                        token);
                 return;
             }
 
@@ -6374,14 +6367,14 @@
      *
      * If we're not replacing the window, clear the replace window settings of the app.
      *
-     * @param token Application token for the activity whose window might be replaced.
+     * @param token     Application token for the activity whose window might be replaced.
      * @param replacing Whether the window is being replaced or not.
      */
     void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) {
         final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
         if (appWindowToken == null) {
-            Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
-                    + token);
+            ProtoLog.w(WM_ERROR, "Attempted to reset replacing window on non-existing app token %s",
+                    token);
             return;
         }
         if (replacing) {
@@ -6570,7 +6563,7 @@
             }
             WindowState callingWin = windowForClientLocked(null, client, false);
             if (callingWin == null) {
-                Slog.w(TAG_WM, "Bad requesting window " + client);
+                ProtoLog.w(WM_ERROR, "Bad requesting window %s", client);
                 return;
             }
             final DisplayContent displayContent = callingWin.getDisplayContent();
@@ -6587,7 +6580,7 @@
                         windowUnderPointer.translateToWindowX(mouseX),
                         windowUnderPointer.translateToWindowY(mouseY));
             } catch (RemoteException e) {
-                Slog.w(TAG_WM, "unable to update pointer icon");
+                ProtoLog.w(WM_ERROR, "unable to update pointer icon");
             }
         }
     }
@@ -6604,7 +6597,7 @@
                         windowUnderPointer.translateToWindowX(latestX),
                         windowUnderPointer.translateToWindowY(latestY));
             } catch (RemoteException e) {
-                Slog.w(TAG_WM, "unable to restore pointer icon");
+                ProtoLog.w(WM_ERROR, "unable to restore pointer icon");
             }
         } else {
             InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_DEFAULT);
@@ -6634,7 +6627,7 @@
             try {
                 final WindowState win = windowForClientLocked(null, client, false);
                 if (win == null) {
-                    Slog.w(TAG_WM, "Bad requesting window " + client);
+                    ProtoLog.w(WM_ERROR, "Bad requesting window %s", client);
                     return;
                 }
                 getDisplayContentOrCreate(displayId, null).reparentDisplayContent(win, sc);
@@ -6659,7 +6652,7 @@
             try {
                 final WindowState win = windowForClientLocked(null, client, false);
                 if (win == null) {
-                    Slog.w(TAG_WM, "Bad requesting window " + client);
+                    ProtoLog.w(WM_ERROR, "Bad requesting window %s", client);
                     return;
                 }
                 final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
@@ -6686,7 +6679,7 @@
         synchronized (mGlobalLock) {
             final WindowState callingWin = windowForClientLocked(null, client, false);
             if (callingWin == null) {
-                Slog.w(TAG_WM, "Bad requesting window " + client);
+                ProtoLog.w(WM_ERROR, "Bad requesting window %s", client);
                 return;
             }
             callingWin.updateTapExcludeRegion(regionId, region);
@@ -6725,8 +6718,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to get windowing mode of a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to get windowing mode of a display that does not exist: %d",
+                        displayId);
                 return WindowConfiguration.WINDOWING_MODE_UNDEFINED;
             }
             return mDisplayWindowSettings.getWindowingModeLocked(displayContent);
@@ -6742,8 +6736,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to set windowing mode to a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to set windowing mode to a display that does not exist: %d",
+                        displayId);
                 return;
             }
 
@@ -6778,8 +6773,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to get remove mode of a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to get remove mode of a display that does not exist: %d",
+                        displayId);
                 return REMOVE_CONTENT_MODE_UNDEFINED;
             }
             return mDisplayWindowSettings.getRemoveContentModeLocked(displayContent);
@@ -6795,8 +6791,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to set remove mode to a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to set remove mode to a display that does not exist: %d",
+                        displayId);
                 return;
             }
 
@@ -6815,8 +6812,8 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to get flag of a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR, "Attempted to get flag of a display that does not exist: %d",
+                        displayId);
                 return false;
             }
             return mDisplayWindowSettings.shouldShowWithInsecureKeyguardLocked(displayContent);
@@ -6833,8 +6830,8 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to set flag to a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: %d",
+                        displayId);
                 return;
             }
 
@@ -6854,8 +6851,8 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to get system decors flag of a display that does "
-                        + "not exist: " + displayId);
+                ProtoLog.w(WM_ERROR, "Attempted to get system decors flag of a display that does "
+                        + "not exist: %d", displayId);
                 return false;
             }
             if (displayContent.isUntrustedVirtualDisplay()) {
@@ -6874,8 +6871,8 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to set system decors flag to a display that does "
-                        + "not exist: " + displayId);
+                ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that does "
+                        + "not exist: %d", displayId);
                 return;
             }
             if (displayContent.isUntrustedVirtualDisplay()) {
@@ -6898,8 +6895,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to get IME flag of a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to get IME flag of a display that does not exist: %d",
+                        displayId);
                 return false;
             }
             if (displayContent.isUntrustedVirtualDisplay()) {
@@ -6919,8 +6917,9 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
             if (displayContent == null) {
-                Slog.w(TAG_WM, "Attempted to set IME flag to a display that does not exist: "
-                        + displayId);
+                ProtoLog.w(WM_ERROR,
+                        "Attempted to set IME flag to a display that does not exist: %d",
+                        displayId);
                 return;
             }
             if (displayContent.isUntrustedVirtualDisplay()) {
@@ -7137,15 +7136,16 @@
                 if (removeWindows) {
                     final DisplayContent dc = mRoot.getDisplayContent(displayId);
                     if (dc == null) {
-                        Slog.w(TAG_WM, "removeWindowToken: Attempted to remove token: " + binder
-                                + " for non-exiting displayId=" + displayId);
+                        ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+                                + " for non-exiting displayId=%d", binder, displayId);
                         return;
                     }
 
                     final WindowToken token = dc.removeWindowToken(binder);
                     if (token == null) {
-                        Slog.w(TAG_WM, "removeWindowToken: Attempted to remove non-existing token: "
-                                + binder);
+                        ProtoLog.w(WM_ERROR,
+                                "removeWindowToken: Attempted to remove non-existing token: %s",
+                                binder);
                         return;
                     }
 
@@ -7748,4 +7748,27 @@
             Binder.restoreCallingIdentity(token);
         }
     }
+
+    @Override
+    public boolean mirrorDisplay(int displayId, SurfaceControl outSurfaceControl) {
+        if (!checkCallingPermission(ACCESS_SURFACE_FLINGER, "mirrorDisplay()")) {
+            throw new SecurityException("Requires ACCESS_SURFACE_FLINGER permission");
+        }
+
+        final SurfaceControl displaySc;
+        synchronized (mGlobalLock) {
+            DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+            if (displayContent == null) {
+                Slog.e(TAG, "Invalid displayId " + displayId + " for mirrorDisplay");
+                return false;
+            }
+
+            displaySc = displayContent.getSurfaceControl();
+        }
+
+        final SurfaceControl mirror = SurfaceControl.mirrorSurface(displaySc);
+        outSurfaceControl.copyFrom(mirror);
+
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0a65e324..569d248 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -90,20 +90,20 @@
 import static com.android.server.wm.MoveAnimationSpecProto.DURATION_MS;
 import static com.android.server.wm.MoveAnimationSpecProto.FROM;
 import static com.android.server.wm.MoveAnimationSpecProto.TO;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -197,6 +197,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.WindowInfo;
+import android.view.WindowInsets.Type.InsetType;
 import android.view.WindowManager;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -206,6 +207,7 @@
 import com.android.internal.policy.KeyInterceptionInfo;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 import com.android.server.wm.utils.InsetUtils;
 import com.android.server.wm.utils.WmDisplayCutout;
@@ -781,7 +783,7 @@
             mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
             mIsChildWindow = true;
 
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + parentWindow);
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", this, parentWindow);
             parentWindow.addChild(this, sWindowSubLayerComparator);
 
             mLayoutAttached = mAttrs.type !=
@@ -1294,14 +1296,11 @@
                 || configChanged
                 || dragResizingChanged
                 || mReportOrientationChanged) {
-            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
-                Slog.v(TAG_WM, "Resize reasons for w=" + this + ": "
-                        + " " + mWindowFrames.getInsetsChangedInfo()
-                        + " surfaceResized=" + winAnimator.mSurfaceResized
-                        + " configChanged=" + configChanged
-                        + " dragResizingChanged=" + dragResizingChanged
-                        + " reportOrientationChanged=" + mReportOrientationChanged);
-            }
+            ProtoLog.v(WM_DEBUG_RESIZE,
+                        "Resize reasons for w=%s:  %s surfaceResized=%b configChanged=%b "
+                                + "dragResizingChanged=%b reportOrientationChanged=%b",
+                        this, mWindowFrames.getInsetsChangedInfo(), winAnimator.mSurfaceResized,
+                        configChanged, dragResizingChanged, mReportOrientationChanged);
 
             // If it's a dead window left on screen, and the configuration changed, there is nothing
             // we can do about it. Remove the window now.
@@ -1318,24 +1317,31 @@
             // redrawn; to do that, we need to go through the process of getting informed by the
             // application when it has finished drawing.
             if (getOrientationChanging() || dragResizingChanged) {
-                if (DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
-                    Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
+                if (getOrientationChanging()) {
+                    Slog.v(TAG_WM, "Orientation start waiting for draw"
                             + ", mDrawState=DRAW_PENDING in " + this
                             + ", surfaceController " + winAnimator.mSurfaceController);
                 }
+                if (dragResizingChanged) {
+                    ProtoLog.v(WM_DEBUG_RESIZE,
+                            "Resize start waiting for draw, "
+                                    + "mDrawState=DRAW_PENDING in %s, surfaceController %s",
+                            this, winAnimator.mSurfaceController);
+                }
                 winAnimator.mDrawState = DRAW_PENDING;
                 if (mAppToken != null) {
                     mAppToken.clearAllDrawn();
                 }
             }
             if (!mWmService.mResizingWindows.contains(this)) {
-                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this);
+                ProtoLog.v(WM_DEBUG_RESIZE, "Resizing window %s", this);
                 mWmService.mResizingWindows.add(this);
             }
         } else if (getOrientationChanging()) {
             if (isDrawnLw()) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in "
-                        + this + ", surfaceController " + winAnimator.mSurfaceController);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Orientation not waiting for draw in %s, surfaceController %s", this,
+                        winAnimator.mSurfaceController);
                 setOrientationChanging(false);
                 mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                         - mWmService.mDisplayFreezeTime);
@@ -1705,7 +1711,7 @@
 
     @Override
     void onMovedByResize() {
-        if (DEBUG_RESIZE) Slog.d(TAG, "onMovedByResize: Moving " + this);
+        ProtoLog.d(WM_DEBUG_RESIZE, "onMovedByResize: Moving %s", this);
         mMovedByResize = true;
         super.onMovedByResize();
     }
@@ -1779,7 +1785,7 @@
     void onResize() {
         final ArrayList<WindowState> resizingWindows = mWmService.mResizingWindows;
         if (mHasSurface && !isGoneForLayoutLw() && !resizingWindows.contains(this)) {
-            if (DEBUG_RESIZE) Slog.d(TAG, "onResize: Resizing " + this);
+            ProtoLog.d(WM_DEBUG_RESIZE, "onResize: Resizing %s", this);
             resizingWindows.add(this);
         }
         if (isGoneForLayoutLw()) {
@@ -1922,8 +1928,8 @@
 
         if (mRemoved) {
             // Nothing to do.
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                    "WS.removeImmediately: " + this + " Already removed...");
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                    "WS.removeImmediately: %s Already removed...", this);
             return;
         }
 
@@ -1973,39 +1979,35 @@
 
     private void removeIfPossible(boolean keepVisibleDeadWindow) {
         mWindowRemovalAllowed = true;
-        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
-                "removeIfPossible: " + this + " callers=" + Debug.getCallers(5));
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                "removeIfPossible: %s callers=%s", this, Debug.getCallers(5));
 
         final boolean startingWindow = mAttrs.type == TYPE_APPLICATION_STARTING;
-        if (startingWindow && DEBUG_STARTING_WINDOW) Slog.d(TAG_WM,
-                "Starting window removed " + this);
-
-        if (DEBUG || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && isFocused()) {
-            Slog.v(TAG_WM, "Remove " + this + " client="
-                    + Integer.toHexString(System.identityHashCode(mClient.asBinder()))
-                    + ", surfaceController=" + mWinAnimator.mSurfaceController + " Callers="
-                    + Debug.getCallers(5));
+        if (startingWindow) {
+            ProtoLog.d(WM_DEBUG_STARTING_WINDOW, "Starting window removed %s", this);
         }
 
+        ProtoLog.v(WM_DEBUG_FOCUS, "Remove client=%x, surfaceController=%s Callers=%s",
+                    System.identityHashCode(mClient.asBinder()),
+                    mWinAnimator.mSurfaceController,
+                    Debug.getCallers(5));
+
+
         final long origId = Binder.clearCallingIdentity();
 
         try {
             disposeInputChannel();
 
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this
-                    + ": mSurfaceController=" + mWinAnimator.mSurfaceController
-                    + " mAnimatingExit=" + mAnimatingExit
-                    + " mRemoveOnExit=" + mRemoveOnExit
-                    + " mHasSurface=" + mHasSurface
-                    + " surfaceShowing=" + mWinAnimator.getShown()
-                    + " animating=" + isAnimating()
-                    + " app-animation="
-                    + (mAppToken != null ? mAppToken.isSelfAnimating() : "false")
-                    + " mWillReplaceWindow=" + mWillReplaceWindow
-                    + " inPendingTransaction="
-                    + (mAppToken != null ? mAppToken.inPendingTransaction : false)
-                    + " mDisplayFrozen=" + mWmService.mDisplayFrozen
-                    + " callers=" + Debug.getCallers(6));
+            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+                    "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b "
+                            + "mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b "
+                            + "mWillReplaceWindow=%b inPendingTransaction=%b mDisplayFrozen=%b "
+                            + "callers=%s",
+                    this, mWinAnimator.mSurfaceController, mAnimatingExit, mRemoveOnExit,
+                    mHasSurface, mWinAnimator.getShown(), isAnimating(),
+                    mAppToken != null && mAppToken.isSelfAnimating(), mWillReplaceWindow,
+                    mAppToken != null && mAppToken.inPendingTransaction,
+                    mWmService.mDisplayFrozen, Debug.getCallers(6));
 
             // Visibility of the removed window. Will be used later to update orientation later on.
             boolean wasVisible = false;
@@ -2017,8 +2019,8 @@
                 if (mWillReplaceWindow) {
                     // This window is going to be replaced. We need to keep it around until the new one
                     // gets added, then we will get rid of this one.
-                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                            "Preserving " + this + " until the new one is " + "added");
+                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                            "Preserving %s until the new one is added", this);
                     // TODO: We are overloading mAnimatingExit flag to prevent the window state from
                     // been removed. We probably need another flag to indicate that window removal
                     // should be deffered vs. overloading the flag that says we are playing an exit
@@ -2032,8 +2034,8 @@
                 wasVisible = isWinVisibleLw();
 
                 if (keepVisibleDeadWindow) {
-                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                            "Not removing " + this + " because app died while it's visible");
+                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                            "Not removing %s because app died while it's visible", this);
 
                     mAppDied = true;
                     setDisplayLayoutNeeded();
@@ -2074,8 +2076,8 @@
                 if (mWinAnimator.getShown() && mAnimatingExit
                         && (!lastWindowIsStartingWindow || isAnimating)) {
                     // The exit animation is running or should run... wait for it!
-                    if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
-                            "Not removing " + this + " due to exit animation ");
+                    ProtoLog.v(WM_DEBUG_ADD_REMOVE,
+                            "Not removing %s due to exit animation", this);
                     setupWindowForRemoveOnExit();
                     if (mAppToken != null) {
                         mAppToken.updateReportedVisibilityLocked();
@@ -2242,7 +2244,7 @@
     }
 
     private void removeReplacedWindow() {
-        if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replaced window: " + this);
+        ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Removing replaced window: %s", this);
         mWillReplaceWindow = false;
         mAnimateReplacingWindow = false;
         mReplacingRemoveRequested = false;
@@ -2398,7 +2400,7 @@
             if (!isVisibleByPolicy()) {
                 mWinAnimator.hide("checkPolicyVisibilityChange");
                 if (isFocused()) {
-                    if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+                    ProtoLog.i(WM_DEBUG_FOCUS_LIGHT,
                             "setAnimationLocked: setting mFocusMayChange true");
                     mWmService.mFocusMayChange = true;
                 }
@@ -2622,8 +2624,24 @@
 
     /** @return false if this window desires touch events. */
     boolean cantReceiveTouchInput() {
-        return mAppToken != null && mAppToken.getTask() != null
-                && (mAppToken.getTask().mStack.shouldIgnoreInput() || mAppToken.hiddenRequested);
+        if (mAppToken == null || mAppToken.getTask() == null) {
+            return false;
+        }
+
+        return mAppToken.getTask().mStack.shouldIgnoreInput()
+                || mAppToken.hiddenRequested
+                || isAnimatingToRecents();
+    }
+
+    /**
+     * Returns {@code true} if the window is animating to home as part of the recents animation.
+     */
+    private boolean isAnimatingToRecents() {
+        final RecentsAnimationController recentsAnimationController =
+                mWmService.getRecentsAnimationController();
+        return recentsAnimationController != null
+                && recentsAnimationController.isAnimatingTask(getTask())
+                && !recentsAnimationController.isTargetApp(mAppToken);
     }
 
     @Override
@@ -2721,7 +2739,7 @@
             // we allow the display to be enabled now.
             mWmService.enableScreenIfNeededLocked();
             if (isFocused) {
-                if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
+                ProtoLog.i(WM_DEBUG_FOCUS_LIGHT,
                         "WindowState.hideLw: setting mFocusMayChange true");
                 mWmService.mFocusMayChange = true;
             }
@@ -2927,7 +2945,8 @@
 
         if (mHasSurface && !getOrientationChanging()
                 && mWmService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
-            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
+            ProtoLog.v(WM_DEBUG_ORIENTATION,
+                    "set mOrientationChanging of %s", this);
             setOrientationChanging(true);
             mWmService.mRoot.mOrientationChangeComplete = false;
         }
@@ -2955,10 +2974,11 @@
         }
 
         if (mDestroying) {
-            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + this
-                    + " destroySurfaces: appStopped=" + appStopped
-                    + " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
-                    + " win.mRemoveOnExit=" + mRemoveOnExit);
+            ProtoLog.e(WM_DEBUG_ADD_REMOVE, "win=%s"
+                    + " destroySurfaces: appStopped=%b"
+                    + " win.mWindowRemovalAllowed=%b"
+                    + " win.mRemoveOnExit=%b", this, appStopped,
+                    mWindowRemovalAllowed, mRemoveOnExit);
             if (!cleanupOnResume || mRemoveOnExit) {
                 destroySurfaceUnchecked();
             }
@@ -3226,16 +3246,19 @@
     void reportResized() {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
         try {
-            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
-                    + ": " + mWindowFrames.mCompatFrame);
+            ProtoLog.v(WM_DEBUG_RESIZE,
+                    "Reporting new frame to %s: %s", this,
+                            mWindowFrames.mCompatFrame);
             final MergedConfiguration mergedConfiguration =
                     new MergedConfiguration(mWmService.mRoot.getConfiguration(),
                     getMergedOverrideConfiguration());
 
             setLastReportedMergedConfiguration(mergedConfiguration);
 
-            if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
-                Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
+            if (mWinAnimator.mDrawState == DRAW_PENDING) {
+                ProtoLog.i(WM_DEBUG_ORIENTATION,
+                        "Resizing %s WITH DRAW PENDING", this);
+            }
 
             final Rect frame = mWindowFrames.mCompatFrame;
             final Rect overscanInsets = mWindowFrames.mLastOverscanInsets;
@@ -3343,6 +3366,15 @@
         }
     }
 
+    @Override
+    public void showInsets(@InsetType int types, boolean fromIme) {
+        try {
+            mClient.showInsets(types, fromIme);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to deliver showInsets", e);
+        }
+    }
+
     Rect getBackdropFrame(Rect frame) {
         // When the task is docked, we send fullscreen sized backDropFrame as soon as resizing
         // start even if we haven't received the relayout window, so that the client requests
@@ -4378,9 +4410,8 @@
             return;
         }
 
-        if (DEBUG || DEBUG_ADD_REMOVE) {
-            Slog.v(TAG, "Exit animation finished in " + this + ": remove=" + mRemoveOnExit);
-        }
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Exit animation finished in %s: remove=%b",
+                this, mRemoveOnExit);
 
         mDestroying = true;
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index c676e72..3dcf6ec 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -27,17 +27,18 @@
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_DRAW;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
@@ -67,6 +68,7 @@
 import android.view.animation.AnimationUtils;
 
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
 
@@ -312,19 +314,19 @@
     boolean finishDrawingLocked(SurfaceControl.Transaction postDrawTransaction) {
         final boolean startingWindow =
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-        if (DEBUG_STARTING_WINDOW && startingWindow) {
-            Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
-                    + drawStateToString());
+        if (startingWindow) {
+            ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finishing drawing window %s: mDrawState=%s",
+                    mWin, drawStateToString());
         }
 
         boolean layoutNeeded = false;
 
         if (mDrawState == DRAW_PENDING) {
-            if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
-                Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + mWin + " in "
-                        + mSurfaceController);
-            if (DEBUG_STARTING_WINDOW && startingWindow) {
-                Slog.v(TAG, "Draw state now committed in " + mWin);
+            ProtoLog.v(WM_DEBUG_DRAW,
+                    "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s", mWin,
+                    mSurfaceController);
+            if (startingWindow) {
+                ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Draw state now committed in %s", mWin);
             }
             mDrawState = COMMIT_DRAW_PENDING;
             layoutNeeded = true;
@@ -385,7 +387,7 @@
             mSurfaceDestroyDeferred = true;
             return;
         }
-        if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "SET FREEZE LAYER", false);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SET FREEZE LAYER: %s", mWin);
         if (mSurfaceController != null) {
             // Our SurfaceControl is always at layer 0 within the parent Surface managed by
             // window-state. We want this old Surface to stay on top of the new one
@@ -456,8 +458,9 @@
 
         w.setHasSurface(false);
 
-        if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
-                "createSurface " + this + ": mDrawState=DRAW_PENDING");
+        if (DEBUG_ANIM) {
+            Slog.i(TAG, "createSurface " + this + ": mDrawState=DRAW_PENDING");
+        }
 
         resetDrawState();
 
@@ -514,15 +517,10 @@
 
             w.setHasSurface(true);
 
-            if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                Slog.i(TAG, "  CREATE SURFACE "
-                        + mSurfaceController + " IN SESSION "
-                        + mSession.mSurfaceSession
-                        + ": pid=" + mSession.mPid + " format="
-                        + attrs.format + " flags=0x"
-                        + Integer.toHexString(flags)
-                        + " / " + this);
-            }
+            ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
+                        "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x / %s",
+                        mSurfaceController, mSession.mSurfaceSession, mSession.mPid, attrs.format,
+                        flags, this);
         } catch (OutOfResourcesException e) {
             Slog.w(TAG, "OutOfResourcesException creating surface");
             mService.mRoot.reclaimSomeSurfaceMemory(this, "create", true);
@@ -616,17 +614,15 @@
             if (mSurfaceDestroyDeferred) {
                 if (mSurfaceController != null && mPendingDestroySurface != mSurfaceController) {
                     if (mPendingDestroySurface != null) {
-                        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                            WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
-                        }
+                        ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY PENDING: %s. %s",
+                                mWin, new RuntimeException().fillInStackTrace());
                         mPendingDestroySurface.destroyNotInTransaction();
                     }
                     mPendingDestroySurface = mSurfaceController;
                 }
             } else {
-                if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                    WindowManagerService.logSurface(mWin, "DESTROY", true);
-                }
+                ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY: %s. %s",
+                        mWin, new RuntimeException().fillInStackTrace());
                 destroySurface();
             }
             // Don't hide wallpaper if we're deferring the surface destroy
@@ -653,9 +649,8 @@
     void destroyDeferredSurfaceLocked() {
         try {
             if (mPendingDestroySurface != null) {
-                if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-                    WindowManagerService.logSurface(mWin, "DESTROY PENDING", true);
-                }
+                ProtoLog.i(WM_SHOW_SURFACE_ALLOC, "SURFACE DESTROY PENDING: %s. %s",
+                        mWin, new RuntimeException().fillInStackTrace());
                 mPendingDestroySurface.destroyNotInTransaction();
                 // Don't hide wallpaper if we're destroying a deferred surface
                 // after a surface mode change.
@@ -673,9 +668,8 @@
     }
 
     void computeShownFrameLocked() {
-        final int displayId = mWin.getDisplayId();
         final ScreenRotationAnimation screenRotationAnimation =
-                mAnimator.getScreenRotationAnimationLocked(displayId);
+                mWin.getDisplayContent().getRotationAnimation();
         final boolean windowParticipatesInScreenRotationAnimation =
                 !mWin.mForceSeamlesslyRotate;
         final boolean screenAnimation = screenRotationAnimation != null
@@ -1089,9 +1083,7 @@
             // There is no need to wait for an animation change if our window is gone for layout
             // already as we'll never be visible.
             if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
-                if (DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Orientation change skips hidden " + w);
-                }
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change skips hidden %s", w);
                 w.setOrientationChanging(false);
             }
             return;
@@ -1116,8 +1108,8 @@
             // before it has drawn for the new orientation.
             if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
                 w.setOrientationChanging(false);
-                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Orientation change skips hidden " + w);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Orientation change skips hidden %s", w);
             }
         } else if (mLastAlpha != mShownAlpha
                 || mLastDsDx != mDsDx
@@ -1135,13 +1127,10 @@
             mLastDtDy = mDtDy;
             w.mLastHScale = w.mHScale;
             w.mLastVScale = w.mVScale;
-            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
-                    "controller=" + mSurfaceController +
-                    "alpha=" + mShownAlpha
-                    + " matrix=[" + mDsDx + "*" + w.mHScale
-                    + "," + mDtDx + "*" + w.mVScale
-                    + "][" + mDtDy + "*" + w.mHScale
-                    + "," + mDsDy + "*" + w.mVScale + "]", false);
+            ProtoLog.i(WM_SHOW_TRANSACTIONS,
+                    "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s",
+                            mSurfaceController, mShownAlpha, mDsDx, w.mHScale, mDtDx, w.mVScale,
+                            mDtDy, w.mHScale, mDsDy, w.mVScale, w);
 
             boolean prepared =
                 mSurfaceController.prepareToShowInTransaction(mShownAlpha,
@@ -1191,11 +1180,11 @@
             if (!w.isDrawnLw()) {
                 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
                 mAnimator.mLastWindowFreezeSource = w;
-                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Orientation continue waiting for draw in " + w);
+                ProtoLog.v(WM_DEBUG_ORIENTATION,
+                        "Orientation continue waiting for draw in %s", w);
             } else {
                 w.setOrientationChanging(false);
-                if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
+                ProtoLog.v(WM_DEBUG_ORIENTATION, "Orientation change complete in %s", w);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 6d813d1..49f27a1 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -21,10 +21,10 @@
 import static android.view.SurfaceControl.METADATA_OWNER_UID;
 import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
 
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowSurfaceControllerProto.LAYER;
@@ -40,6 +40,8 @@
 import android.view.SurfaceSession;
 import android.view.WindowContentFrameStats;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.io.PrintWriter;
 
 class WindowSurfaceController {
@@ -111,31 +113,22 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
-    private void logSurface(String msg, RuntimeException where) {
-        String str = "  SURFACE " + msg + ": " + title;
-        if (where != null) {
-            Slog.i(TAG, str, where);
-        } else {
-            Slog.i(TAG, str);
-        }
-    }
-
     void reparentChildrenInTransaction(WindowSurfaceController other) {
-        if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "REPARENT from: %s to: %s", this, other);
         if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
             mSurfaceControl.reparentChildren(other.mSurfaceControl);
         }
     }
 
     void detachChildren() {
-        if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SEVER CHILDREN");
         if (mSurfaceControl != null) {
             mSurfaceControl.detachChildren();
         }
     }
 
     void hide(SurfaceControl.Transaction transaction, String reason) {
-        if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE HIDE ( %s ): %s", reason, title);
         mHiddenForOtherReasons = true;
 
         mAnimator.destroyPreservedSurfaceLocked();
@@ -157,9 +150,8 @@
     }
 
     void destroyNotInTransaction() {
-        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-            Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
-        }
+        ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
+                    "Destroying surface %s called by %s", this, Debug.getCallers(8));
         try {
             if (mSurfaceControl != null) {
                 mTmpTransaction.remove(mSurfaceControl).apply();
@@ -173,8 +165,7 @@
     }
 
     void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
-        if (SHOW_TRANSACTIONS) logSurface(
-                "CROP " + clipRect.toShortString(), null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE CROP %s: %s", clipRect.toShortString(), title);
         try {
             if (clipRect.width() > 0 && clipRect.height() > 0) {
                 if (!clipRect.equals(mSurfaceCrop)) {
@@ -198,8 +189,7 @@
     }
 
     void clearCropInTransaction(boolean recoveringMemory) {
-        if (SHOW_TRANSACTIONS) logSurface(
-                "CLEAR CROP", null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE CLEAR CROP: %s", title);
         try {
             Rect clipRect = new Rect(0, 0, -1, -1);
             if (mSurfaceCrop.equals(clipRect)) {
@@ -227,8 +217,8 @@
             mSurfaceY = top;
 
             try {
-                if (SHOW_TRANSACTIONS) logSurface(
-                        "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
+                ProtoLog.i(WM_SHOW_TRANSACTIONS,
+                        "SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", left, top, title);
 
                 if (t == null) {
                     mSurfaceControl.setPosition(left, top);
@@ -264,8 +254,8 @@
         mLastDsdy = dsdy;
 
         try {
-            if (SHOW_TRANSACTIONS) logSurface(
-                    "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null);
+            ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE MATRIX [%f,%f,%f,%f]: %s",
+                    dsdx, dtdx, dtdy, dsdy, title);
             if (t == null) {
                 mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
             } else {
@@ -290,8 +280,7 @@
             mSurfaceH = height;
 
             try {
-                if (SHOW_TRANSACTIONS) logSurface(
-                        "SIZE " + width + "x" + height, null);
+                ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SIZE %dx%d: %s", width, height, title);
                 mSurfaceControl.setBufferSize(width, height);
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such
@@ -350,8 +339,7 @@
     }
 
     void setOpaque(boolean isOpaque) {
-        if (SHOW_TRANSACTIONS) logSurface("isOpaque=" + isOpaque,
-                null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isOpaque=%b: %s", isOpaque, title);
 
         if (mSurfaceControl == null) {
             return;
@@ -367,8 +355,7 @@
     }
 
     void setSecure(boolean isSecure) {
-        if (SHOW_TRANSACTIONS) logSurface("isSecure=" + isSecure,
-                null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isSecure=%b: %s", isSecure, title);
 
         if (mSurfaceControl == null) {
             return;
@@ -384,9 +371,7 @@
     }
 
     void setColorSpaceAgnostic(boolean agnostic) {
-        if (SHOW_TRANSACTIONS) {
-            logSurface("isColorSpaceAgnostic=" + agnostic, null);
-        }
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE isColorSpaceAgnostic=%b: %s", agnostic, title);
 
         if (mSurfaceControl == null) {
             return;
@@ -410,8 +395,7 @@
     }
 
     boolean showRobustlyInTransaction() {
-        if (SHOW_TRANSACTIONS) logSurface(
-                "SHOW (performLayout)", null);
+        ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE SHOW (performLayout): %s", title);
         if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
                 + " during relayout");
         mHiddenForOtherReasons = false;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 8aee0f2..fbfb028 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -19,9 +19,9 @@
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
@@ -35,9 +35,10 @@
 import android.annotation.CallSuper;
 import android.os.Debug;
 import android.os.IBinder;
-import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.server.protolog.common.ProtoLog;
+
 import java.io.PrintWriter;
 import java.util.Comparator;
 
@@ -135,8 +136,8 @@
     void removeAllWindowsIfPossible() {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final WindowState win = mChildren.get(i);
-            if (DEBUG_WINDOW_MOVEMENT) Slog.w(TAG_WM,
-                    "removeAllWindowsIfPossible: removing win=" + win);
+            ProtoLog.w(WM_DEBUG_WINDOW_MOVEMENT,
+                    "removeAllWindowsIfPossible: removing win=%s", win);
             win.removeIfPossible();
         }
     }
@@ -197,15 +198,15 @@
     }
 
     void addWindow(final WindowState win) {
-        if (DEBUG_FOCUS) Slog.d(TAG_WM,
-                "addWindow: win=" + win + " Callers=" + Debug.getCallers(5));
+        ProtoLog.d(WM_DEBUG_FOCUS,
+                "addWindow: win=%s Callers=%s", win, Debug.getCallers(5));
 
         if (win.isChildWindow()) {
             // Child windows are added to their parent windows.
             return;
         }
         if (!mChildren.contains(win)) {
-            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Adding " + win + " to " + this);
+            ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Adding %s to %s", win, this);
             addChild(win, mWindowComparator);
             mWmService.mWindowsChanged = true;
             // TODO: Should we also be setting layout needed here and other places?
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index d9c7fed..bcd1713 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -141,6 +141,7 @@
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
         "android.hardware.vibrator@1.3",
+        "android.hardware.vibrator@1.4",
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index d5fbd2b..a8c7682 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -16,17 +16,12 @@
 
 #define LOG_TAG "VibratorService"
 
-#include <android/hardware/vibrator/1.0/IVibrator.h>
-#include <android/hardware/vibrator/1.0/types.h>
-#include <android/hardware/vibrator/1.0/IVibrator.h>
-#include <android/hardware/vibrator/1.1/types.h>
-#include <android/hardware/vibrator/1.2/IVibrator.h>
-#include <android/hardware/vibrator/1.2/types.h>
-#include <android/hardware/vibrator/1.3/IVibrator.h>
+#include <android/hardware/vibrator/1.4/IVibrator.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include "android_runtime/AndroidRuntime.h"
+#include "core_jni_helpers.h"
 
 #include <utils/misc.h>
 #include <utils/Log.h>
@@ -36,6 +31,7 @@
 #include <stdio.h>
 
 using android::hardware::Return;
+using android::hardware::Void;
 using android::hardware::vibrator::V1_0::EffectStrength;
 using android::hardware::vibrator::V1_0::Status;
 using android::hardware::vibrator::V1_1::Effect_1_1;
@@ -44,9 +40,32 @@
 namespace V1_1 = android::hardware::vibrator::V1_1;
 namespace V1_2 = android::hardware::vibrator::V1_2;
 namespace V1_3 = android::hardware::vibrator::V1_3;
+namespace V1_4 = android::hardware::vibrator::V1_4;
 
 namespace android {
 
+static jmethodID sMethodIdOnComplete;
+
+class VibratorCallback : public V1_4::IVibratorCallback {
+    public:
+        VibratorCallback(JNIEnv *env, jobject vibration) :
+        mVibration(MakeGlobalRefOrDie(env, vibration)) {}
+
+        ~VibratorCallback() {
+            JNIEnv *env = AndroidRuntime::getJNIEnv();
+            env->DeleteGlobalRef(mVibration);
+        }
+
+        Return<void> onComplete() override {
+            auto env = AndroidRuntime::getJNIEnv();
+            env->CallVoidMethod(mVibration, sMethodIdOnComplete);
+            return Void();
+        }
+
+    private:
+        jobject mVibration;
+};
+
 static constexpr int NUM_TRIES = 2;
 
 // Creates a Return<R> with STATUS::EX_NULL_POINTER.
@@ -56,37 +75,57 @@
     return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)};
 }
 
-// Helper used to transparently deal with the vibrator HAL becoming unavailable.
+template <typename I>
+class HalWrapper {
+  public:
+    static std::unique_ptr<HalWrapper> Create() {
+        // Assume that if getService returns a nullptr, HAL is not available on the
+        // device.
+        auto hal = I::getService();
+        return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr;
+    }
+
+    // Helper used to transparently deal with the vibrator HAL becoming unavailable.
+    template<class R, class... Args0, class... Args1>
+    Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
+        // Return<R> doesn't have a default constructor, so make a Return<R> with
+        // STATUS::EX_NONE.
+        using ::android::hardware::Status;
+        Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};
+
+        // Note that ret is guaranteed to be changed after this loop.
+        for (int i = 0; i < NUM_TRIES; ++i) {
+            ret = (mHal == nullptr) ? NullptrStatus<R>()
+                    : (*mHal.*fn)(std::forward<Args1>(args1)...);
+
+            if (ret.isOk()) {
+                break;
+            }
+
+            ALOGE("Failed to issue command to vibrator HAL. Retrying.");
+            // Restoring connection to the HAL.
+            mHal = I::tryGetService();
+        }
+        return ret;
+    }
+
+  private:
+    HalWrapper(sp<I> &&hal) : mHal(std::move(hal)) {}
+
+  private:
+    sp<I> mHal;
+};
+
+template <typename I>
+static auto getHal() {
+    static auto sHalWrapper = HalWrapper<I>::Create();
+    return sHalWrapper.get();
+}
+
 template<class R, class I, class... Args0, class... Args1>
 Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) {
-    // Assume that if getService returns a nullptr, HAL is not available on the
-    // device.
-    static sp<I> sHal = I::getService();
-    static bool sAvailable = sHal != nullptr;
-
-    if (!sAvailable) {
-        return NullptrStatus<R>();
-    }
-
-    // Return<R> doesn't have a default constructor, so make a Return<R> with
-    // STATUS::EX_NONE.
-    using ::android::hardware::Status;
-    Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)};
-
-    // Note that ret is guaranteed to be changed after this loop.
-    for (int i = 0; i < NUM_TRIES; ++i) {
-        ret = (sHal == nullptr) ? NullptrStatus<R>()
-                : (*sHal.*fn)(std::forward<Args1>(args1)...);
-
-        if (ret.isOk()) {
-            break;
-        }
-
-        ALOGE("Failed to issue command to vibrator HAL. Retrying.");
-        // Restoring connection to the HAL.
-        sHal = I::tryGetService();
-    }
-    return ret;
+    auto hal = getHal<I>();
+    return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>();
 }
 
 template<class R>
@@ -99,17 +138,17 @@
     return val >= *iter.begin() && val <= *std::prev(iter.end());
 }
 
-static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
+static void vibratorInit(JNIEnv *env, jclass clazz)
 {
     halCall(&V1_0::IVibrator::ping).isOk();
 }
 
-static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
+static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
 {
     return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
-static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
+static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
 {
     Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
@@ -117,7 +156,7 @@
     }
 }
 
-static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
+static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
 {
     Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
@@ -125,11 +164,11 @@
     }
 }
 
-static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
+static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
     return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
 }
 
-static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
+static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
     Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
         .withDefault(Status::UNKNOWN_ERROR);
     if (status != Status::OK) {
@@ -138,11 +177,11 @@
     }
 }
 
-static jboolean vibratorSupportsExternalControl(JNIEnv*, jobject) {
+static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
     return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
 }
 
-static void vibratorSetExternalControl(JNIEnv*, jobject, jboolean enabled) {
+static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
     Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
         .withDefault(Status::UNKNOWN_ERROR);
     if (status != Status::OK) {
@@ -151,7 +190,8 @@
     }
 }
 
-static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength) {
+static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jint strength,
+                                   jobject vibration) {
     Status status;
     uint32_t lengthMs;
     auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) {
@@ -161,7 +201,11 @@
     EffectStrength effectStrength(static_cast<EffectStrength>(strength));
 
     Return<void> ret;
-    if (isValidEffect<V1_0::Effect>(effect)) {
+    if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) {
+        sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration);
+        ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect),
+                effectStrength, effectCallback, callback);
+    } else if (isValidEffect<V1_0::Effect>(effect)) {
         ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
                 effectStrength, callback);
     } else if (isValidEffect<Effect_1_1>(effect)) {
@@ -198,6 +242,10 @@
     return -1;
 }
 
+static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
+    return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0);
+}
+
 static const JNINativeMethod method_table[] = {
     { "vibratorExists", "()Z", (void*)vibratorExists },
     { "vibratorInit", "()V", (void*)vibratorInit },
@@ -205,13 +253,18 @@
     { "vibratorOff", "()V", (void*)vibratorOff },
     { "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
     { "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
-    { "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect},
+    { "vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;)J",
+        (void*)vibratorPerformEffect},
     { "vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
     { "vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
+    { "vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
 };
 
 int register_android_server_VibratorService(JNIEnv *env)
 {
+    sMethodIdOnComplete = GetMethodIDOrDie(env,
+            FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
+            "onComplete", "()V");
     return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
             method_table, NELEM(method_table));
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 03f4755..fb2fdab1 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -159,12 +159,7 @@
     status_t status = android_view_PointerIcon_loadSystemIcon(env,
             contextObj, style, outPointerIcon);
     if (!status) {
-        SkBitmap* bitmapCopy = &outSpriteIcon->bitmap;
-        SkImageInfo bitmapCopyInfo = outPointerIcon->bitmap.info().makeColorType(kN32_SkColorType);
-        if (bitmapCopy->tryAllocPixels(bitmapCopyInfo)) {
-            outPointerIcon->bitmap.readPixels(bitmapCopy->info(), bitmapCopy->getPixels(),
-                    bitmapCopy->rowBytes(), 0, 0);
-        }
+        outSpriteIcon->bitmap = outPointerIcon->bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888);
         outSpriteIcon->style = outPointerIcon->style;
         outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX;
         outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY;
@@ -1575,6 +1570,27 @@
     im->setSystemUiVisibility(visibility);
 }
 
+static jboolean nativeTransferTouchFocus(JNIEnv* env,
+        jclass /* clazz */, jlong ptr, jobject fromChannelObj, jobject toChannelObj) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    sp<InputChannel> fromChannel =
+            android_view_InputChannel_getInputChannel(env, fromChannelObj);
+    sp<InputChannel> toChannel =
+            android_view_InputChannel_getInputChannel(env, toChannelObj);
+
+    if (fromChannel == nullptr || toChannel == nullptr) {
+        return JNI_FALSE;
+    }
+
+    if (im->getInputManager()->getDispatcher()->
+            transferTouchFocus(fromChannel->getToken(), toChannel->getToken())) {
+        return JNI_TRUE;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 static void nativeSetPointerSpeed(JNIEnv* /* env */,
         jclass /* clazz */, jlong ptr, jint speed) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
@@ -1709,15 +1725,8 @@
         return;
     }
 
-    SpriteIcon spriteIcon;
-    SkImageInfo spriteInfo = pointerIcon.bitmap.info().makeColorType(kN32_SkColorType);
-    if (spriteIcon.bitmap.tryAllocPixels(spriteInfo)) {
-        pointerIcon.bitmap.readPixels(spriteInfo, spriteIcon.bitmap.getPixels(),
-                spriteIcon.bitmap.rowBytes(), 0, 0);
-    }
-    spriteIcon.style = pointerIcon.style;
-    spriteIcon.hotSpotX = pointerIcon.hotSpotX;
-    spriteIcon.hotSpotY = pointerIcon.hotSpotY;
+    SpriteIcon spriteIcon(pointerIcon.bitmap.copy(ANDROID_BITMAP_FORMAT_RGBA_8888),
+                          pointerIcon.style, pointerIcon.hotSpotX, pointerIcon.hotSpotY);
     im->setCustomPointerIcon(spriteIcon);
 }
 
@@ -1775,6 +1784,8 @@
             (void*) nativeSetInputDispatchMode },
     { "nativeSetSystemUiVisibility", "(JI)V",
             (void*) nativeSetSystemUiVisibility },
+    { "nativeTransferTouchFocus", "(JLandroid/view/InputChannel;Landroid/view/InputChannel;)Z",
+            (void*) nativeTransferTouchFocus },
     { "nativeSetPointerSpeed", "(JI)V",
             (void*) nativeSetPointerSpeed },
     { "nativeSetShowTouches", "(JZ)V",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 479dd1e..c3ff285 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -126,6 +126,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManager.PasswordComplexity;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DeviceStateCache;
 import android.app.admin.NetworkEvent;
 import android.app.admin.PasswordMetrics;
 import android.app.admin.SecurityLog;
@@ -507,6 +508,7 @@
     private final OverlayPackagesProvider mOverlayPackagesProvider;
 
     private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl();
+    private final DeviceStateCacheImpl mStateCache = new DeviceStateCacheImpl();
 
     /**
      * Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
@@ -2295,6 +2297,9 @@
                 policy = new DevicePolicyData(userHandle);
                 mUserData.append(userHandle, policy);
                 loadSettingsLocked(policy, userHandle);
+                if (userHandle == UserHandle.USER_SYSTEM) {
+                    mStateCache.setDeviceProvisioned(policy.mUserSetupComplete);
+                }
             }
             return policy;
         }
@@ -8958,6 +8963,8 @@
             pw.println("Encryption Status: " + getEncryptionStatusName(getEncryptionStatus()));
             pw.println();
             mPolicyCache.dump(pw);
+            pw.println();
+            mStateCache.dump(pw);
         }
     }
 
@@ -11169,6 +11176,9 @@
                 DevicePolicyData policy = getUserData(userHandle);
                 if (!policy.mUserSetupComplete) {
                     policy.mUserSetupComplete = true;
+                    if (userHandle == UserHandle.USER_SYSTEM) {
+                        mStateCache.setDeviceProvisioned(true);
+                    }
                     synchronized (getLockObject()) {
                         saveSettingsLocked(userHandle);
                     }
@@ -11481,6 +11491,12 @@
         protected DevicePolicyCache getDevicePolicyCache() {
             return mPolicyCache;
         }
+
+        @Override
+        protected DeviceStateCache getDeviceStateCache() {
+            return mStateCache;
+        }
+
     }
 
     private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {
@@ -13021,6 +13037,7 @@
                 Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0;
         DevicePolicyData policy = getUserData(userId);
         policy.mUserSetupComplete = isUserCompleted;
+        mStateCache.setDeviceProvisioned(isUserCompleted);
         synchronized (getLockObject()) {
             saveSettingsLocked(userId);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
new file mode 100644
index 0000000..c3cb9b0
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceStateCacheImpl.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import android.app.admin.DeviceStateCache;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+
+/**
+ * Implementation of {@link DeviceStateCache}, to which {@link DevicePolicyManagerService} pushes
+ * device state.
+ *
+ */
+public class DeviceStateCacheImpl extends DeviceStateCache {
+    /**
+     * Lock object. For simplicity we just always use this as the lock. We could use each object
+     * as a lock object to make it more fine-grained, but that'd make copy-paste error-prone.
+     */
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    private boolean mIsDeviceProvisioned = false;
+
+    @Override
+    public boolean isDeviceProvisioned() {
+        return mIsDeviceProvisioned;
+    }
+
+    /** Update the device provisioned flag for USER_SYSTEM */
+    public void setDeviceProvisioned(boolean provisioned) {
+        synchronized (mLock) {
+            mIsDeviceProvisioned = provisioned;
+        }
+    }
+
+    /** Dump content */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("Device state cache:");
+        pw.increaseIndent();
+        pw.println("Device provisioned: " + mIsDeviceProvisioned);
+        pw.decreaseIndent();
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 90d0c30..de65002 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -141,7 +141,6 @@
 import com.android.server.security.KeyChainSystemService;
 import com.android.server.signedconfig.SignedConfigService;
 import com.android.server.soundtrigger.SoundTriggerService;
-import com.android.server.stats.StatsCompanionService;
 import com.android.server.statusbar.StatusBarManagerService;
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
@@ -202,6 +201,8 @@
             "com.android.server.print.PrintManagerService";
     private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS =
             "com.android.server.companion.CompanionDeviceManagerService";
+    private static final String STATS_COMPANION_SERVICE_LIFECYCLE_CLASS =
+            "com.android.server.stats.StatsCompanionService$Lifecycle";
     private static final String USB_SERVICE_CLASS =
             "com.android.server.usb.UsbService$Lifecycle";
     private static final String MIDI_SERVICE_CLASS =
@@ -803,7 +804,7 @@
 
         // Manages Overlay packages
         t.traceBegin("StartOverlayManagerService");
-        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext));
         t.traceEnd();
 
         t.traceBegin("StartSensorPrivacyService");
@@ -1875,7 +1876,7 @@
 
         // Statsd helper
         t.traceBegin("StartStatsCompanionService");
-        mSystemServiceManager.startService(StatsCompanionService.Lifecycle.class);
+        mSystemServiceManager.startService(STATS_COMPANION_SERVICE_LIFECYCLE_CLASS);
         t.traceEnd();
 
         // Incidentd and dumpstated helper
diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java
index af9e601..31a2556 100644
--- a/services/net/java/android/net/netlink/InetDiagMessage.java
+++ b/services/net/java/android/net/netlink/InetDiagMessage.java
@@ -16,26 +16,23 @@
 
 package android.net.netlink;
 
-import static android.os.Process.INVALID_UID;
 import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY;
 import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
+import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.NETLINK_INET_DIAG;
 
-import android.os.Build;
-import android.os.Process;
+import android.net.util.SocketUtils;
 import android.system.ErrnoException;
 import android.util.Log;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.InterruptedIOException;
-import java.net.DatagramSocket;
-import java.net.DatagramSocket;
-import java.net.InetAddress;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetSocketAddress;
@@ -163,17 +160,25 @@
      */
     public static int getConnectionOwnerUid(int protocol, InetSocketAddress local,
                                             InetSocketAddress remote) {
+        int uid = INVALID_UID;
+        FileDescriptor fd = null;
         try {
-            final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
+            fd = NetlinkSocket.forProto(NETLINK_INET_DIAG);
             NetlinkSocket.connectToKernel(fd);
-
-            return lookupUid(protocol, local, remote, fd);
-
+            uid = lookupUid(protocol, local, remote, fd);
         } catch (ErrnoException | SocketException | IllegalArgumentException
                 | InterruptedIOException e) {
             Log.e(TAG, e.toString());
+        } finally {
+            if (fd != null) {
+                try {
+                    SocketUtils.closeSocket(fd);
+                } catch (IOException e) {
+                    Log.e(TAG, e.toString());
+                }
+            }
         }
-        return INVALID_UID;
+        return uid;
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index f1142fd..36e854c 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -46,7 +46,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.RemoteException;
-import android.util.Log;
 import android.view.Display;
 import android.view.InputDevice;
 import android.view.KeyEvent;
@@ -55,6 +54,8 @@
 
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.accessibility.utils.MotionEventMatcher;
+
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
@@ -761,56 +762,6 @@
         return next;
     }
 
-    static class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> {
-        long mDownTime;
-        long mEventTime;
-        long mActionMasked;
-        int mX;
-        int mY;
-
-        MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) {
-            mDownTime = downTime;
-            mEventTime = eventTime;
-            mActionMasked = actionMasked;
-            mX = x;
-            mY = y;
-        }
-
-        MotionEventMatcher(MotionEvent event) {
-            this(event.getDownTime(), event.getEventTime(), event.getActionMasked(),
-                    (int) event.getX(), (int) event.getY());
-        }
-
-        void offsetTimesBy(long timeOffset) {
-            mDownTime += timeOffset;
-            mEventTime += timeOffset;
-        }
-
-        @Override
-        public boolean matchesSafely(MotionEvent event) {
-            if ((event.getDownTime() == mDownTime) && (event.getEventTime() == mEventTime)
-                    && (event.getActionMasked() == mActionMasked) && ((int) event.getX() == mX)
-                    && ((int) event.getY() == mY)) {
-                return true;
-            }
-            Log.e(LOG_TAG, "MotionEvent match failed");
-            Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime()
-                    + ", expected " + mDownTime);
-            Log.e(LOG_TAG, "event.getEventTime() = " + event.getEventTime()
-                    + ", expected " + mEventTime);
-            Log.e(LOG_TAG, "event.getActionMasked() = " + event.getActionMasked()
-                    + ", expected " + mActionMasked);
-            Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX);
-            Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY);
-            return false;
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("Motion event matcher");
-        }
-    }
-
     private static class MotionEventActionMatcher extends TypeSafeMatcher<MotionEvent> {
         int mAction;
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 104aacb..4b1ec6f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -21,6 +21,7 @@
 import static com.android.server.accessibility.gestures.TouchState.STATE_DRAGGING;
 import static com.android.server.accessibility.gestures.TouchState.STATE_TOUCH_EXPLORING;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
@@ -36,6 +37,7 @@
 
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.utils.MotionEventMatcher;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -49,6 +51,7 @@
 @RunWith(AndroidJUnit4.class)
 public class TouchExplorerTest {
 
+    private static final String LOG_TAG = "TouchExplorerTest";
     private static final int FLAG_1FINGER = 0x8000;
     private static final int FLAG_2FINGERS = 0x0100;
     private static final int FLAG_3FINGERS = 0x0200;
@@ -86,7 +89,9 @@
 
         @Override
         public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+            MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent);
             mEvents.add(0, event.copy());
+            assertThat(rawEvent, lastEventMatcher);
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java
new file mode 100644
index 0000000..2b6d385
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/utils/MotionEventMatcher.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility.utils;
+
+import android.util.Log;
+import android.view.MotionEvent;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+
+/**
+ * This class compares two motion events using a subset of their attributes: actionMasked, downTime,
+ * eventTime, and location. If two events match they are considered to be effectively equal.
+ */
+public class MotionEventMatcher extends TypeSafeMatcher<MotionEvent> {
+    private static final String LOG_TAG = "MotionEventMatcher";
+    long mDownTime;
+    long mEventTime;
+    long mActionMasked;
+    int mX;
+    int mY;
+
+    MotionEventMatcher(long downTime, long eventTime, int actionMasked, int x, int y) {
+        mDownTime = downTime;
+        mEventTime = eventTime;
+        mActionMasked = actionMasked;
+        mX = x;
+        mY = y;
+    }
+
+    public MotionEventMatcher(MotionEvent event) {
+        this(
+                event.getDownTime(),
+                event.getEventTime(),
+                event.getActionMasked(),
+                (int) event.getX(),
+                (int) event.getY());
+    }
+
+    void offsetTimesBy(long timeOffset) {
+        mDownTime += timeOffset;
+        mEventTime += timeOffset;
+    }
+
+    @Override
+    public boolean matchesSafely(MotionEvent event) {
+        if ((event.getDownTime() == mDownTime)
+                && (event.getEventTime() == mEventTime)
+                && (event.getActionMasked() == mActionMasked)
+                && ((int) event.getX() == mX)
+                && ((int) event.getY() == mY)) {
+            return true;
+        }
+        Log.e(LOG_TAG, "MotionEvent match failed");
+        Log.e(LOG_TAG, "event.getDownTime() = " + event.getDownTime() + ", expected " + mDownTime);
+        Log.e(
+                LOG_TAG,
+                "event.getEventTime() = " + event.getEventTime() + ", expected " + mEventTime);
+        Log.e(
+                LOG_TAG,
+                "event.getActionMasked() = "
+                        + event.getActionMasked()
+                        + ", expected "
+                        + mActionMasked);
+        Log.e(LOG_TAG, "event.getX() = " + event.getX() + ", expected " + mX);
+        Log.e(LOG_TAG, "event.getY() = " + event.getY() + ", expected " + mY);
+        return false;
+    }
+
+    @Override
+    public void describeTo(Description description) {
+        description.appendText("Motion event matcher");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
index 9e3b54d..c3a1243 100644
--- a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -16,10 +16,8 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.MemoryStatUtil.BYTES_IN_KILOBYTE;
-import static com.android.server.am.MemoryStatUtil.JIFFY_NANOS;
 import static com.android.server.am.MemoryStatUtil.MemoryStat;
-import static com.android.server.am.MemoryStatUtil.parseCmdlineFromProcfs;
+import static com.android.server.am.MemoryStatUtil.PAGE_SIZE;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromMemcg;
 import static com.android.server.am.MemoryStatUtil.parseMemoryStatFromProcfs;
 
@@ -30,7 +28,6 @@
 
 import org.junit.Test;
 
-import java.io.ByteArrayOutputStream;
 import java.util.Collections;
 
 /**
@@ -99,7 +96,7 @@
             "0",
             "2222", // this in start time (in ticks per second)
             "1257177088",
-            "3",
+            "3", // this is RSS in pages
             "4294967295",
             "2936971264",
             "2936991289",
@@ -129,53 +126,6 @@
             "3198889956",
             "0");
 
-    private static final String PROC_STATUS_CONTENTS = "Name:\tandroid.youtube\n"
-            + "State:\tS (sleeping)\n"
-            + "Tgid:\t12088\n"
-            + "Pid:\t12088\n"
-            + "PPid:\t723\n"
-            + "TracerPid:\t0\n"
-            + "Uid:\t10083\t10083\t10083\t10083\n"
-            + "Gid:\t10083\t10083\t10083\t10083\n"
-            + "Ngid:\t0\n"
-            + "FDSize:\t128\n"
-            + "Groups:\t3003 9997 20083 50083 \n"
-            + "VmPeak:\t 4546844 kB\n"
-            + "VmSize:\t 4542636 kB\n"
-            + "VmLck:\t       0 kB\n"
-            + "VmPin:\t       0 kB\n"
-            + "VmHWM:\t  137668 kB\n" // RSS high-water mark
-            + "VmRSS:\t  126776 kB\n" // RSS
-            + "RssAnon:\t   37860 kB\n"
-            + "RssFile:\t   88764 kB\n"
-            + "RssShmem:\t     152 kB\n"
-            + "VmData:\t 4125112 kB\n"
-            + "VmStk:\t    8192 kB\n"
-            + "VmExe:\t      24 kB\n"
-            + "VmLib:\t  102432 kB\n"
-            + "VmPTE:\t    1300 kB\n"
-            + "VmPMD:\t      36 kB\n"
-            + "VmSwap:\t      22 kB\n" // Swap
-            + "Threads:\t95\n"
-            + "SigQ:\t0/13641\n"
-            + "SigPnd:\t0000000000000000\n"
-            + "ShdPnd:\t0000000000000000\n"
-            + "SigBlk:\t0000000000001204\n"
-            + "SigIgn:\t0000000000000001\n"
-            + "SigCgt:\t00000006400084f8\n"
-            + "CapInh:\t0000000000000000\n"
-            + "CapPrm:\t0000000000000000\n"
-            + "CapEff:\t0000000000000000\n"
-            + "CapBnd:\t0000000000000000\n"
-            + "CapAmb:\t0000000000000000\n"
-            + "Seccomp:\t2\n"
-            + "Cpus_allowed:\tff\n"
-            + "Cpus_allowed_list:\t0-7\n"
-            + "Mems_allowed:\t1\n"
-            + "Mems_allowed_list:\t0\n"
-            + "voluntary_ctxt_switches:\t903\n"
-            + "nonvoluntary_ctxt_switches:\t104\n";
-
     @Test
     public void testParseMemoryStatFromMemcg_parsesCorrectValues() {
         MemoryStat stat = parseMemoryStatFromMemcg(MEMORY_STAT_CONTENTS);
@@ -197,71 +147,26 @@
 
     @Test
     public void testParseMemoryStatFromProcfs_parsesCorrectValues() {
-        MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, PROC_STATUS_CONTENTS);
+        MemoryStat stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS);
         assertEquals(1, stat.pgfault);
         assertEquals(2, stat.pgmajfault);
-        assertEquals(126776 * BYTES_IN_KILOBYTE, stat.rssInBytes);
+        assertEquals(3 * PAGE_SIZE, stat.rssInBytes);
         assertEquals(0, stat.cacheInBytes);
-        assertEquals(22 * BYTES_IN_KILOBYTE, stat.swapInBytes);
-        assertEquals(2222 * JIFFY_NANOS, stat.startTimeNanos);
-        assertEquals(37860 * BYTES_IN_KILOBYTE, stat.anonRssInBytes);
+        assertEquals(0, stat.swapInBytes);
     }
 
     @Test
     public void testParseMemoryStatFromProcfs_emptyContents() {
-        MemoryStat stat = parseMemoryStatFromProcfs("", PROC_STATUS_CONTENTS);
+        MemoryStat stat = parseMemoryStatFromProcfs("");
         assertNull(stat);
 
-        stat = parseMemoryStatFromProcfs(null, PROC_STATUS_CONTENTS);
-        assertNull(stat);
-
-        stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, "");
-        assertNull(stat);
-
-        stat = parseMemoryStatFromProcfs(PROC_STAT_CONTENTS, null);
+        stat = parseMemoryStatFromProcfs(null);
         assertNull(stat);
     }
 
     @Test
     public void testParseMemoryStatFromProcfs_invalidValue() {
         String contents = String.join(" ", Collections.nCopies(24, "memory"));
-        assertNull(parseMemoryStatFromProcfs(contents, PROC_STATUS_CONTENTS));
-    }
-
-    @Test
-    public void testParseCmdlineFromProcfs_invalidValue() {
-        byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
-
-        assertEquals("", parseCmdlineFromProcfs(bytesToString(nothing)));
-    }
-
-    @Test
-    public void testParseCmdlineFromProcfs_correctValue_noNullBytes() {
-        assertEquals("com.google.app", parseCmdlineFromProcfs("com.google.app"));
-    }
-
-    @Test
-    public void testParseCmdlineFromProcfs_correctValue_withNullBytes() {
-        byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
-
-        assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
-
-        // test\0\0test
-        byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
-
-        assertEquals("test", parseCmdlineFromProcfs(bytesToString(trailing)));
-    }
-
-    @Test
-    public void testParseCmdlineFromProcfs_emptyContents() {
-        assertEquals("", parseCmdlineFromProcfs(""));
-
-        assertEquals("", parseCmdlineFromProcfs(null));
-    }
-
-    private static String bytesToString(byte[] bytes) {
-        ByteArrayOutputStream output = new ByteArrayOutputStream();
-        output.write(bytes, 0, bytes.length);
-        return output.toString();
+        assertNull(parseMemoryStatFromProcfs(contents));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index d4b7e7e9..79cc3db 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -25,8 +25,8 @@
 import static com.android.server.am.UserController.REPORT_LOCKED_BOOT_COMPLETE_MSG;
 import static com.android.server.am.UserController.REPORT_USER_SWITCH_COMPLETE_MSG;
 import static com.android.server.am.UserController.REPORT_USER_SWITCH_MSG;
-import static com.android.server.am.UserController.SYSTEM_USER_CURRENT_MSG;
-import static com.android.server.am.UserController.SYSTEM_USER_START_MSG;
+import static com.android.server.am.UserController.USER_CURRENT_MSG;
+import static com.android.server.am.UserController.USER_START_MSG;
 import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
 
 import static com.google.android.collect.Lists.newArrayList;
@@ -53,11 +53,13 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
 import android.app.IUserSwitchObserver;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.UserInfo;
+import android.content.pm.UserInfo.UserInfoFlag;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -106,6 +108,10 @@
     private static final int TEST_USER_ID1 = 101;
     private static final int TEST_USER_ID2 = 102;
     private static final int NONEXIST_USER_ID = 2;
+    private static final int TEST_PRE_CREATED_USER_ID = 103;
+
+    private static final int NO_USERINFO_FLAGS = 0;
+
     private static final String TAG = UserControllerTest.class.getSimpleName();
 
     private static final long HANDLER_WAIT_TIME_MS = 100;
@@ -127,11 +133,11 @@
     private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES = newHashSet(
             REPORT_USER_SWITCH_MSG,
             USER_SWITCH_TIMEOUT_MSG,
-            SYSTEM_USER_START_MSG,
-            SYSTEM_USER_CURRENT_MSG);
+            USER_START_MSG,
+            USER_CURRENT_MSG);
 
     private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
-            SYSTEM_USER_START_MSG,
+            USER_START_MSG,
             REPORT_LOCKED_BOOT_COMPLETE_MSG);
 
     @Before
@@ -148,7 +154,8 @@
             doNothing().when(mInjector).clearBroadcastQueueForUser(anyInt());
             doNothing().when(mInjector).stackSupervisorRemoveUser(anyInt());
             mUserController = new UserController(mInjector);
-            setUpUser(TEST_USER_ID, 0);
+            setUpUser(TEST_USER_ID, NO_USERINFO_FLAGS);
+            setUpUser(TEST_PRE_CREATED_USER_ID, NO_USERINFO_FLAGS, /* preCreated=*/ true);
         });
     }
 
@@ -188,6 +195,31 @@
         startForegroundUserAssertions();
     }
 
+    @Test
+    public void testStartPreCreatedUser_foreground() {
+        assertFalse(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ true));
+    }
+
+    @Test
+    public void testStartPreCreatedUser_background() throws Exception {
+        assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ false));
+
+        verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
+        verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
+        verify(mInjector, never()).clearAllLockedTasks(anyString());
+
+        assertWithMessage("should not have received intents")
+                .that(getActions(mInjector.mSentIntents)).isEmpty();
+        // TODO(b/140868593): should have received a USER_UNLOCK_MSG message as well, but it doesn't
+        // because StorageManager.isUserKeyUnlocked(TEST_PRE_CREATED_USER_ID) returns false - to
+        // properly fix it, we'd need to move this class to FrameworksMockingServicesTests so we can
+        // mock static methods (but moving this class would involve changing the presubmit tests,
+        // and the cascade effect goes on...). In fact, a better approach would to not assert the
+        // binder calls, but their side effects (in this case, that the user is stopped right away)
+        assertWithMessage("wrong binder message calls").that(mInjector.mHandler.getMessageCodes())
+                .containsExactly(USER_START_MSG);
+    }
+
     private void startUserAssertions(
             List<String> expectedActions, Set<Integer> expectedMessageCodes) {
         assertEquals(expectedActions, getActions(mInjector.mSentIntents));
@@ -467,9 +499,15 @@
         continueUserSwitchAssertions(newUserId, expectOldUserStopping);
     }
 
-    private void setUpUser(int userId, int flags) {
+    private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags) {
+        setUpUser(userId, flags, /* preCreated= */ false);
+    }
+
+    private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags, boolean preCreated) {
         UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
+        userInfo.preCreated = preCreated;
         when(mInjector.mUserManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
+        when(mInjector.mUserManagerMock.isPreCreated(userId)).thenReturn(preCreated);
     }
 
     private static List<String> getActions(List<Intent> intents) {
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index 70650de..66d2bab 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -89,11 +89,13 @@
         final int defaultModeOp2 = AppOpsManager.opToDefaultMode(op2);
         for(int i = 0; i < uidStates.size(); i++) {
             final AppOpsService.UidState uidState = uidStates.valueAt(i);
-            final int uidMode1 = uidState.hasOpMode(op1) ? uidState.getOpMode(op1) : defaultModeOp1;
-            final int uidMode2 = uidState.hasOpMode(op2) ? uidState.getOpMode(op2) : defaultModeOp2;
-            assertEquals(uidMode1, uidMode2);
-            if (uidMode1 != defaultModeOp1) {
-                numberOfNonDefaultOps++;
+            if (uidState.opModes != null) {
+                final int uidMode1 = uidState.opModes.get(op1, defaultModeOp1);
+                final int uidMode2 = uidState.opModes.get(op2, defaultModeOp2);
+                assertEquals(uidMode1, uidMode2);
+                if (uidMode1 != defaultModeOp1) {
+                    numberOfNonDefaultOps++;
+                }
             }
             if (uidState.pkgOps == null) {
                 continue;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 1f5ebe4..7cece1f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -29,6 +29,7 @@
 import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DeviceStateCache;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
 import android.content.pm.UserInfo;
@@ -37,6 +38,7 @@
 import android.os.IProgressListener;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
 import android.security.KeyStore;
@@ -91,6 +93,8 @@
     FakeGsiService mGsiService;
     PasswordSlotManagerTestable mPasswordSlotManager;
     RecoverableKeyStoreManager mRecoverableKeyStoreManager;
+    UserManagerInternal mUserManagerInternal;
+    DeviceStateCache mDeviceStateCache;
     protected boolean mHasSecureLockScreen;
 
     @Override
@@ -108,6 +112,8 @@
         mGsiService = new FakeGsiService();
         mPasswordSlotManager = new PasswordSlotManagerTestable();
         mRecoverableKeyStoreManager = mock(RecoverableKeyStoreManager.class);
+        mUserManagerInternal = mock(UserManagerInternal.class);
+        mDeviceStateCache = mock(DeviceStateCache.class);
 
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -144,7 +150,8 @@
         mAuthSecretService = mock(IAuthSecret.class);
         mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
                 mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
-                mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager);
+                mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager,
+                mUserManagerInternal, mDeviceStateCache);
         when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
         mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
         installChildProfile(MANAGED_PROFILE_USER_ID);
@@ -172,6 +179,9 @@
         // Adding a fake Device Owner app which will enable escrow token support in LSS.
         when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
                 new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
+        when(mUserManagerInternal.isDeviceManaged()).thenReturn(true);
+        when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
+
         mLocalService = LocalServices.getService(LockSettingsInternal.class);
     }
 
@@ -184,6 +194,7 @@
         when(mUserManager.getProfileParent(eq(profileId))).thenReturn(PRIMARY_USER_INFO);
         when(mUserManager.isUserRunning(eq(profileId))).thenReturn(true);
         when(mUserManager.isUserUnlocked(eq(profileId))).thenReturn(true);
+        when(mUserManagerInternal.isUserManaged(eq(profileId))).thenReturn(true);
         return userInfo;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 5c67d04..65d6f45 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -19,12 +19,14 @@
 import static org.mockito.Mockito.mock;
 
 import android.app.IActivityManager;
+import android.app.admin.DeviceStateCache;
 import android.content.Context;
 import android.hardware.authsecret.V1_0.IAuthSecret;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserManagerInternal;
 import android.os.storage.IStorageManager;
 import android.security.KeyStore;
 import android.security.keystore.KeyPermanentlyInvalidatedException;
@@ -44,15 +46,16 @@
         private LockPatternUtils mLockPatternUtils;
         private IStorageManager mStorageManager;
         private SyntheticPasswordManager mSpManager;
-        private IAuthSecret mAuthSecretService;
         private FakeGsiService mGsiService;
         private RecoverableKeyStoreManager mRecoverableKeyStoreManager;
+        private UserManagerInternal mUserManagerInternal;
+        private DeviceStateCache mDeviceStateCache;
 
         public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
                 IActivityManager activityManager, LockPatternUtils lockPatternUtils,
                 IStorageManager storageManager, SyntheticPasswordManager spManager,
-                IAuthSecret authSecretService, FakeGsiService gsiService,
-                RecoverableKeyStoreManager recoverableKeyStoreManager) {
+                FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
+                UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
             super(context);
             mLockSettingsStorage = storage;
             mKeyStore = keyStore;
@@ -62,6 +65,8 @@
             mSpManager = spManager;
             mGsiService = gsiService;
             mRecoverableKeyStoreManager = recoverableKeyStoreManager;
+            mUserManagerInternal = userManagerInternal;
+            mDeviceStateCache = deviceStateCache;
         }
 
         @Override
@@ -93,6 +98,10 @@
         public LockPatternUtils getLockPatternUtils() {
             return mLockPatternUtils;
         }
+        @Override
+        public DeviceStateCache getDeviceStateCache() {
+            return mDeviceStateCache;
+        }
 
         @Override
         public KeyStore getKeyStore() {
@@ -110,6 +119,11 @@
         }
 
         @Override
+        public UserManagerInternal getUserManagerInternal() {
+            return mUserManagerInternal;
+        }
+
+        @Override
         public boolean hasEnrolledBiometrics(int userId) {
             return false;
         }
@@ -134,10 +148,11 @@
             LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore,
             IStorageManager storageManager, IActivityManager mActivityManager,
             SyntheticPasswordManager spManager, IAuthSecret authSecretService,
-            FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager) {
+            FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
+            UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
         super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils,
-                storageManager, spManager, authSecretService, gsiService,
-                recoverableKeyStoreManager));
+                storageManager, spManager, gsiService,
+                recoverableKeyStoreManager, userManagerInternal, deviceStateCache));
         mGateKeeperService = gatekeeper;
         mAuthSecretService = authSecretService;
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 127cf49..0776589 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -29,6 +29,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.admin.PasswordMetrics;
 import android.os.RemoteException;
@@ -468,6 +469,18 @@
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
     }
 
+    public void testEscrowTokenCannotBeActivatedOnUnmanagedUser() {
+        final byte[] token = "some-high-entropy-secure-token".getBytes();
+        when(mUserManagerInternal.isDeviceManaged()).thenReturn(false);
+        when(mUserManagerInternal.isUserManaged(PRIMARY_USER_ID)).thenReturn(false);
+        when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
+
+        try {
+            mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
+            fail("Escrow token should not be possible on unmanaged device");
+        } catch (SecurityException expected) { }
+    }
+
     public void testSetLockCredentialWithTokenFailsWithoutLockScreen() throws Exception {
         final byte[] password = "password".getBytes();
         final byte[] pattern = "123654".getBytes();
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 3cdadd5..c566dfc 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -444,7 +444,7 @@
         private Set<String> mIdmapFiles = new ArraySet<>();
 
         DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) {
-            super(null, packageManagerHelper);
+            super(packageManagerHelper);
             mState = state;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 3fe9b52..15032c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -20,8 +20,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.res.Resources.ID_NULL;
 
-import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.notNullValue;
@@ -75,10 +75,11 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerSettingsTests {
+    private static final String TAG = "PackageManagerSettingsTests";
+    private static final String PACKAGE_NAME_1 = "com.android.app1";
     private static final String PACKAGE_NAME_2 = "com.android.app2";
     private static final String PACKAGE_NAME_3 = "com.android.app3";
-    private static final String PACKAGE_NAME_1 = "com.android.app1";
-    public static final String TAG = "PackageManagerSettingsTests";
+    private static final int TEST_RESOURCE_ID = 2131231283;
 
     @Mock
     PermissionSettings mPermissionSettings;
@@ -158,7 +159,7 @@
         assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
     }
 
-    private PersistableBundle getPersistableBundle(String packageName, long longVal,
+    private static PersistableBundle createPersistableBundle(String packageName, long longVal,
             double doubleVal, boolean boolVal, String textVal) {
         final PersistableBundle bundle = new PersistableBundle();
         bundle.putString(packageName + ".TEXT_VALUE", textVal);
@@ -169,8 +170,8 @@
     }
 
     @Test
-    public void testReadPackageRestrictions_oldSuspendInfo() {
-        writePackageRestrictions_oldSuspendInfoXml(0);
+    public void testReadPackageRestrictions_noSuspendingPackage() {
+        writePackageRestrictions_noSuspendingPackageXml(0);
         final Object lock = new Object();
         final Context context = InstrumentationRegistry.getTargetContext();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
@@ -181,26 +182,61 @@
         final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
         final PackageUserState packageUserState1 = ps1.readUserState(0);
         assertThat(packageUserState1.suspended, is(true));
-        assertThat("android".equals(packageUserState1.suspendingPackage), is(true));
+        assertThat(packageUserState1.suspendParams.size(), is(1));
+        assertThat(packageUserState1.suspendParams.keyAt(0), is("android"));
+        assertThat(packageUserState1.suspendParams.valueAt(0), is(nullValue()));
 
         final PackageSetting ps2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2);
         final PackageUserState packageUserState2 = ps2.readUserState(0);
         assertThat(packageUserState2.suspended, is(false));
-        assertThat(packageUserState2.suspendingPackage, is(nullValue()));
+        assertThat(packageUserState2.suspendParams, is(nullValue()));
     }
 
     @Test
-    public void testReadWritePackageRestrictions_newSuspendInfo() {
+    public void testReadPackageRestrictions_noSuspendParamsMap() {
+        writePackageRestrictions_noSuspendParamsMapXml(0);
+        final Object lock = new Object();
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+        settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+        settingsUnderTest.readPackageRestrictionsLPr(0);
+
+        final PackageSetting ps1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1);
+        final PackageUserState packageUserState1 = ps1.readUserState(0);
+        assertThat(packageUserState1.suspended, is(true));
+        assertThat(packageUserState1.suspendParams.size(), is(1));
+        assertThat(packageUserState1.suspendParams.keyAt(0), is(PACKAGE_NAME_3));
+        final PackageUserState.SuspendParams params = packageUserState1.suspendParams.valueAt(0);
+        assertThat(params, is(notNullValue()));
+        assertThat(params.appExtras.size(), is(1));
+        assertThat(params.appExtras.getString("app_extra_string"), is("value"));
+        assertThat(params.launcherExtras.size(), is(1));
+        assertThat(params.launcherExtras.getLong("launcher_extra_long"), is(4L));
+        assertThat(params.dialogInfo, is(notNullValue()));
+        assertThat(params.dialogInfo.getDialogMessage(), is("Dialog Message"));
+        assertThat(params.dialogInfo.getTitleResId(), is(ID_NULL));
+        assertThat(params.dialogInfo.getIconResId(), is(TEST_RESOURCE_ID));
+        assertThat(params.dialogInfo.getNeutralButtonTextResId(), is(ID_NULL));
+        assertThat(params.dialogInfo.getDialogMessageResId(), is(ID_NULL));
+    }
+
+    @Test
+    public void testReadWritePackageRestrictions_suspendInfo() {
         final Context context = InstrumentationRegistry.getTargetContext();
         final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
         final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
         final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
         final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
 
-        final PersistableBundle appExtras1 = getPersistableBundle(
+        final PersistableBundle appExtras1 = createPersistableBundle(
                 PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
-        final PersistableBundle launcherExtras1 = getPersistableBundle(
+        final PersistableBundle appExtras2 = createPersistableBundle(
+                PACKAGE_NAME_2, 2L, 0.02, true, "appString2");
+
+        final PersistableBundle launcherExtras1 = createPersistableBundle(
                 PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
+        final PersistableBundle launcherExtras2 = createPersistableBundle(
+                PACKAGE_NAME_2, 20L, 0.2, false, "launcherString2");
 
         final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
                 .setIcon(0x11220001)
@@ -208,14 +244,23 @@
                 .setMessage("1st message")
                 .setNeutralButtonText(0x11220003)
                 .build();
+        final SuspendDialogInfo dialogInfo2 = new SuspendDialogInfo.Builder()
+                .setIcon(0x22220001)
+                .setTitle(0x22220002)
+                .setMessage("2nd message")
+                .setNeutralButtonText(0x22220003)
+                .build();
 
-        ps1.setSuspended(true, "suspendingPackage1", dialogInfo1, appExtras1, launcherExtras1, 0);
+        ps1.addOrUpdateSuspension("suspendingPackage1", dialogInfo1, appExtras1, launcherExtras1,
+                0);
+        ps1.addOrUpdateSuspension("suspendingPackage2", dialogInfo2, appExtras2, launcherExtras2,
+                0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
 
-        ps2.setSuspended(true, "suspendingPackage2", null, null, null, 0);
+        ps2.addOrUpdateSuspension("suspendingPackage3", null, appExtras1, null, 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
 
-        ps3.setSuspended(false, "irrelevant", dialogInfo1, null, null, 0);
+        ps3.removeSuspension("irrelevant", 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
 
         settingsUnderTest.writePackageRestrictionsLPr(0);
@@ -229,27 +274,39 @@
         final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
                 .readUserState(0);
         assertThat(readPus1.suspended, is(true));
-        assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
-        assertThat(readPus1.dialogInfo, equalTo(dialogInfo1));
-        assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
-        assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
+        assertThat(readPus1.suspendParams.size(), is(2));
+
+        assertThat(readPus1.suspendParams.keyAt(0), is("suspendingPackage1"));
+        final PackageUserState.SuspendParams params11 = readPus1.suspendParams.valueAt(0);
+        assertThat(params11, is(notNullValue()));
+        assertThat(params11.dialogInfo, is(dialogInfo1));
+        assertThat(BaseBundle.kindofEquals(params11.appExtras, appExtras1), is(true));
+        assertThat(BaseBundle.kindofEquals(params11.launcherExtras, launcherExtras1),
+                is(true));
+
+        assertThat(readPus1.suspendParams.keyAt(1), is("suspendingPackage2"));
+        final PackageUserState.SuspendParams params12 = readPus1.suspendParams.valueAt(1);
+        assertThat(params12, is(notNullValue()));
+        assertThat(params12.dialogInfo, is(dialogInfo2));
+        assertThat(BaseBundle.kindofEquals(params12.appExtras, appExtras2), is(true));
+        assertThat(BaseBundle.kindofEquals(params12.launcherExtras, launcherExtras2),
                 is(true));
 
         final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
                 .readUserState(0);
         assertThat(readPus2.suspended, is(true));
-        assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
-        assertThat(readPus2.dialogInfo, is(nullValue()));
-        assertThat(readPus2.suspendedAppExtras, is(nullValue()));
-        assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
+        assertThat(readPus2.suspendParams.size(), is(1));
+        assertThat(readPus2.suspendParams.keyAt(0), is("suspendingPackage3"));
+        final PackageUserState.SuspendParams params21 = readPus2.suspendParams.valueAt(0);
+        assertThat(params21, is(notNullValue()));
+        assertThat(params21.dialogInfo, is(nullValue()));
+        assertThat(BaseBundle.kindofEquals(params21.appExtras, appExtras1), is(true));
+        assertThat(params21.launcherExtras, is(nullValue()));
 
         final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
                 .readUserState(0);
         assertThat(readPus3.suspended, is(false));
-        assertThat(readPus3.suspendingPackage, is(nullValue()));
-        assertThat(readPus3.dialogInfo, is(nullValue()));
-        assertThat(readPus3.suspendedAppExtras, is(nullValue()));
-        assertThat(readPus3.suspendedLauncherExtras, is(nullValue()));
+        assertThat(readPus3.suspendParams, is(nullValue()));
     }
 
     @Test
@@ -940,10 +997,10 @@
                 + "</packages>").getBytes());
     }
 
-    private void writePackageRestrictions_oldSuspendInfoXml(final int userId) {
+    private void writePackageRestrictions_noSuspendingPackageXml(final int userId) {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/"
                         + userId + "/package-restrictions.xml"),
-                ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
                         + "<package-restrictions>\n"
                         + "    <pkg name=\"" + PACKAGE_NAME_1 + "\" suspended=\"true\" />"
                         + "    <pkg name=\"" + PACKAGE_NAME_2 + "\" suspended=\"false\" />"
@@ -955,6 +1012,30 @@
                         .getBytes());
     }
 
+    private void writePackageRestrictions_noSuspendParamsMapXml(final int userId) {
+        writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/users/"
+                        + userId + "/package-restrictions.xml"),
+                ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                        + "<package-restrictions>\n"
+                        + "    <pkg name=\"" + PACKAGE_NAME_1 + "\" "
+                        + "     suspended=\"true\" suspending-package=\"" + PACKAGE_NAME_3 + "\">\n"
+                        + "        <suspended-dialog-info dialogMessage=\"Dialog Message\""
+                        + "         iconResId=\"" + TEST_RESOURCE_ID + "\"/>\n"
+                        + "        <suspended-app-extras>\n"
+                        + "            <string name=\"app_extra_string\">value</string>\n"
+                        + "        </suspended-app-extras>\n"
+                        + "        <suspended-launcher-extras>\n"
+                        + "            <long name=\"launcher_extra_long\" value=\"4\" />\n"
+                        + "        </suspended-launcher-extras>\n"
+                        + "    </pkg>\n"
+                        + "    <preferred-activities />\n"
+                        + "    <persistent-preferred-activities />\n"
+                        + "    <crossProfile-intent-filters />\n"
+                        + "    <default-apps />\n"
+                        + "</package-restrictions>\n")
+                        .getBytes());
+    }
+
     private void writeStoppedPackagesXml() {
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(), "system/packages-stopped.xml"),
                 ( "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 8eaf35f..fc5a0ba 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -26,6 +26,7 @@
 import android.content.pm.PackageUserState;
 import android.content.pm.SuspendDialogInfo;
 import android.os.PersistableBundle;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 
 import androidx.test.filters.SmallTest;
@@ -175,18 +176,43 @@
         assertThat(testUserState03.equals(oldUserState), is(false));
     }
 
+    private static PackageUserState.SuspendParams createSuspendParams(SuspendDialogInfo dialogInfo,
+            PersistableBundle appExtras, PersistableBundle launcherExtras) {
+        PackageUserState.SuspendParams obj = PackageUserState.SuspendParams.getInstanceOrNull(
+                dialogInfo, appExtras, launcherExtras);
+        return obj;
+    }
+
+    private static PersistableBundle createPersistableBundle(String lKey, long lValue, String sKey,
+            String sValue, String dKey, double dValue) {
+        final PersistableBundle result = new PersistableBundle(3);
+        if (lKey != null) {
+            result.putLong("com.unit_test." + lKey, lValue);
+        }
+        if (sKey != null) {
+            result.putString("com.unit_test." + sKey, sValue);
+        }
+        if (dKey != null) {
+            result.putDouble("com.unit_test." + dKey, dValue);
+        }
+        return result;
+    }
+
     @Test
     public void testPackageUserState05() {
-        PersistableBundle appExtras1 = new PersistableBundle();
-        PersistableBundle appExtras2 = new PersistableBundle();
-        appExtras1.putInt("appExtraId", 1);
-        appExtras2.putInt("appExtraId", 2);
-        PersistableBundle launcherExtras1 = new PersistableBundle();
-        PersistableBundle launcherExtras2 = new PersistableBundle();
-        launcherExtras1.putString("name", "launcherExtras1");
-        launcherExtras2.putString("name", "launcherExtras2");
+        final PersistableBundle appExtras1 = createPersistableBundle("appExtraId", 1, null, null,
+                null, 0);
+        final PersistableBundle appExtras2 = createPersistableBundle("appExtraId", 2, null, null,
+                null, 0);
+
+        final PersistableBundle launcherExtras1 = createPersistableBundle(null, 0, "name",
+                "launcherExtras1", null, 0);
+        final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
+                "launcherExtras2", null, 0);
+
         final String suspendingPackage1 = "package1";
         final String suspendingPackage2 = "package2";
+
         final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
                 .setMessage("dialogMessage1")
                 .build();
@@ -194,38 +220,23 @@
                 .setMessage("dialogMessage2")
                 .build();
 
+        final ArrayMap<String, PackageUserState.SuspendParams> paramsMap1 = new ArrayMap<>();
+        paramsMap1.put(suspendingPackage1, createSuspendParams(dialogInfo1, appExtras1,
+                launcherExtras1));
+        final ArrayMap<String, PackageUserState.SuspendParams> paramsMap2 = new ArrayMap<>();
+        paramsMap2.put(suspendingPackage2, createSuspendParams(dialogInfo2,
+                appExtras2, launcherExtras2));
+
+
         final PackageUserState testUserState1 = new PackageUserState();
         testUserState1.suspended = true;
-        testUserState1.suspendedAppExtras = appExtras1;
-        testUserState1.suspendedLauncherExtras = launcherExtras1;
-        testUserState1.suspendingPackage = suspendingPackage1;
-        testUserState1.dialogInfo = dialogInfo1;
+        testUserState1.suspendParams = paramsMap1;
 
         PackageUserState testUserState2 = new PackageUserState(testUserState1);
         assertThat(testUserState1.equals(testUserState2), is(true));
-        testUserState2.suspendingPackage = suspendingPackage2;
+        testUserState2.suspendParams = paramsMap2;
+        // Should not be equal since suspendParams maps are different
         assertThat(testUserState1.equals(testUserState2), is(false));
-
-        testUserState2 = new PackageUserState(testUserState1);
-        testUserState2.suspendedAppExtras = appExtras2;
-        assertThat(testUserState1.equals(testUserState2), is(false));
-
-        testUserState2 = new PackageUserState(testUserState1);
-        testUserState2.suspendedLauncherExtras = launcherExtras2;
-        assertThat(testUserState1.equals(testUserState2), is(false));
-
-        testUserState2 = new PackageUserState(testUserState1);
-        testUserState2.dialogInfo = dialogInfo2;
-        assertThat(testUserState1.equals(testUserState2), is(false));
-
-        testUserState2 = new PackageUserState(testUserState1);
-        testUserState2.suspended = testUserState1.suspended = false;
-        // Everything is different but irrelevant if suspended is false
-        testUserState2.suspendingPackage = suspendingPackage2;
-        testUserState2.dialogInfo = dialogInfo2;
-        testUserState2.suspendedAppExtras = appExtras2;
-        testUserState2.suspendedLauncherExtras = launcherExtras2;
-        assertThat(testUserState1.equals(testUserState2), is(true));
     }
 
     @Test
@@ -243,4 +254,46 @@
         assertThat(userState1.equals(userState2), is(false));
     }
 
+    @Test
+    public void testPackageUserState07() {
+        final PersistableBundle appExtras1 = createPersistableBundle("appExtraId", 1, null, null,
+                null, 0);
+        final PersistableBundle appExtras2 = createPersistableBundle("appExtraId", 2, null, null,
+                null, 0);
+
+        final PersistableBundle launcherExtras1 = createPersistableBundle(null, 0, "name",
+                "launcherExtras1", null, 0);
+        final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
+                "launcherExtras2", null, 0);
+
+        final SuspendDialogInfo dialogInfo1 = new SuspendDialogInfo.Builder()
+                .setMessage("dialogMessage1")
+                .build();
+        final SuspendDialogInfo dialogInfo2 = new SuspendDialogInfo.Builder()
+                .setMessage("dialogMessage2")
+                .build();
+
+        final PackageUserState.SuspendParams params1;
+        PackageUserState.SuspendParams params2;
+        params1 = createSuspendParams(dialogInfo1, appExtras1, launcherExtras1);
+        params2 = createSuspendParams(dialogInfo1, appExtras1, launcherExtras1);
+        // Everything is same
+        assertThat(params1.equals(params2), is(true));
+
+        params2 = createSuspendParams(dialogInfo2, appExtras1, launcherExtras1);
+        // DialogInfo is different
+        assertThat(params1.equals(params2), is(false));
+
+        params2 = createSuspendParams(dialogInfo1, appExtras2, launcherExtras1);
+        // app extras are different
+        assertThat(params1.equals(params2), is(false));
+
+        params2 = createSuspendParams(dialogInfo1, appExtras1, launcherExtras2);
+        // Launcher extras are different
+        assertThat(params1.equals(params2), is(false));
+
+        params2 = createSuspendParams(dialogInfo2, appExtras2, launcherExtras2);
+        // Everything is different
+        assertThat(params1.equals(params2), is(false));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 0b8c2a55..0c5451f 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.rollback;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
@@ -271,15 +270,4 @@
 
         inOrder.verifyNoMoreInteractions();
     }
-
-    @Test
-    public void snapshotAddDataSavesSnapshottedUsersToInfo() {
-        Installer installer = mock(Installer.class);
-        AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
-
-        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
-        helper.snapshotAppData(5, info, new int[]{10, 11});
-
-        assertArrayEquals(info.getSnapshottedUsers().toArray(), new int[]{10, 11});
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index b5925a6..151b6e2 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -18,22 +18,48 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.util.IntArray;
 import android.util.SparseLongArray;
 
+import com.google.common.collect.Range;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.io.File;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 
 @RunWith(JUnit4.class)
 public class RollbackUnitTest {
 
+    private static final String PKG_1 = "test.testpackage.pkg1";
+    private static final String PKG_2 = "test.testpackage.pkg2";
+    private static final String PKG_3 = "com.blah.hello.three";
+    private static final String PKG_4 = "com.something.4pack";
+
+    @Mock private AppDataRollbackHelper mMockDataHelper;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
     @Test
     public void newEmptyStagedRollbackDefaults() {
         int rollbackId = 123;
@@ -61,82 +87,229 @@
     }
 
     @Test
-    public void rollbackStateChanges() {
+    public void rollbackMadeAvailable() {
         Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
 
         assertThat(rollback.isEnabling()).isTrue();
         assertThat(rollback.isAvailable()).isFalse();
         assertThat(rollback.isCommitted()).isFalse();
 
-        rollback.setAvailable();
+        Instant availableTime = Instant.now();
+        rollback.makeAvailable();
 
         assertThat(rollback.isEnabling()).isFalse();
         assertThat(rollback.isAvailable()).isTrue();
         assertThat(rollback.isCommitted()).isFalse();
 
-        rollback.setCommitted();
+        assertThat(rollback.getTimestamp()).isIn(Range.closed(availableTime, Instant.now()));
+    }
 
-        assertThat(rollback.isEnabling()).isFalse();
+    @Test
+    public void deletedRollbackCannotBeMadeAvailable() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+
+        rollback.delete(mMockDataHelper);
+
+        assertThat(rollback.isDeleted()).isTrue();
+
+        rollback.makeAvailable();
+
         assertThat(rollback.isAvailable()).isFalse();
-        assertThat(rollback.isCommitted()).isTrue();
+        assertThat(rollback.isDeleted()).isTrue();
     }
 
     @Test
     public void getPackageNamesAllAndJustApex() {
-        String pkg1 = "test.testpackage.pkg1";
-        String pkg2 = "test.testpackage.pkg2";
-        String pkg3 = "com.blah.hello.three";
-        String pkg4 = "com.something.4pack";
-
         Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
-        PackageRollbackInfo pkgInfo1 = pkgInfoFor(pkg1, 12, 10, false);
-        PackageRollbackInfo pkgInfo2 = pkgInfoFor(pkg2, 12, 10, true);
-        PackageRollbackInfo pkgInfo3 = pkgInfoFor(pkg3, 12, 10, false);
-        PackageRollbackInfo pkgInfo4 = pkgInfoFor(pkg4, 12, 10, true);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 11, true);
+        PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 19, 1, false);
+        PackageRollbackInfo pkgInfo4 = newPkgInfoFor(PKG_4, 12, 1, true);
 
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2, pkgInfo3, pkgInfo4));
 
-        assertThat(rollback.getPackageNames()).containsExactly(pkg1, pkg2, pkg3, pkg4);
-        assertThat(rollback.getApexPackageNames()).containsExactly(pkg2, pkg4);
+        assertThat(rollback.getPackageNames()).containsExactly(PKG_1, PKG_2, PKG_3, PKG_4);
+        assertThat(rollback.getApexPackageNames()).containsExactly(PKG_2, PKG_4);
     }
 
     @Test
-    public void includesPackages() {
-        String pkg1 = "test.testpackage.pkg1";
-        String pkg2 = "test.testpackage.pkg2";
-        String pkg3 = "com.blah.hello.three";
-        String pkg4 = "com.something.4pack";
-
+    public void includesPackagesAfterEnable() {
         Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
-        PackageRollbackInfo pkgInfo1 = pkgInfoFor(pkg1, 12, 10, false);
-        PackageRollbackInfo pkgInfo2 = pkgInfoFor(pkg2, 18, 12, true);
-        PackageRollbackInfo pkgInfo3 = pkgInfoFor(pkg3, 157, 156, false);
-        PackageRollbackInfo pkgInfo4 = pkgInfoFor(pkg4, 99, 1, true);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        PackageRollbackInfo pkgInfo3 = newPkgInfoFor(PKG_3, 157, 156, false);
+        PackageRollbackInfo pkgInfo4 = newPkgInfoFor(PKG_4, 99, 1, true);
 
         rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2, pkgInfo3, pkgInfo4));
 
-        assertThat(rollback.includesPackage(pkg2)).isTrue();
-        assertThat(rollback.includesPackage(pkg3)).isTrue();
+        assertThat(rollback.includesPackage(PKG_2)).isTrue();
+        assertThat(rollback.includesPackage(PKG_3)).isTrue();
         assertThat(rollback.includesPackage("com.something.else")).isFalse();
 
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg1, 12)).isFalse();
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg1, 1)).isTrue();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_1, 12)).isFalse();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_1, 1)).isTrue();
 
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg2, 18)).isFalse();
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg2, 12)).isTrue();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_2, 18)).isFalse();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_2, 12)).isTrue();
 
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 157)).isFalse();
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 156)).isTrue();
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg3, 15)).isTrue();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 157)).isFalse();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 156)).isTrue();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_3, 15)).isTrue();
 
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg4, 99)).isFalse();
-        assertThat(rollback.includesPackageWithDifferentVersion(pkg4, 100)).isTrue();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_4, 99)).isFalse();
+        assertThat(rollback.includesPackageWithDifferentVersion(PKG_4, 100)).isTrue();
     }
 
-    private static PackageRollbackInfo pkgInfoFor(
+    @Test
+    public void snapshotWhenEnabling() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        assertThat(rollback.isEnabling()).isTrue();
+
+        int[] userIds = {4, 77};
+        rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper);
+
+        // Data is snapshotted for the specified package.
+        verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds));
+        verify(mMockDataHelper, never())
+                .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any());
+    }
+
+    @Test
+    public void snapshotWhenAvailable() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        rollback.makeAvailable();
+
+        assertThat(rollback.isAvailable()).isTrue();
+
+        int[] userIds = {4, 77};
+        rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper);
+
+        // No data is snapshotted as rollback was not in the enabling state.
+        verify(mMockDataHelper, never())
+                .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any());
+        verify(mMockDataHelper, never())
+                .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_2), any());
+    }
+
+    @Test
+    public void snapshotWhenDeleted() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        rollback.delete(mMockDataHelper);
+
+        assertThat(rollback.isDeleted()).isTrue();
+
+        int[] userIds = {4, 77};
+        rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper);
+
+        // No data is snapshotted as rollback was not in the enabling state.
+        verify(mMockDataHelper, never())
+                .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_1), any());
+        verify(mMockDataHelper, never())
+                .snapshotAppData(anyInt(), pkgRollbackInfoFor(PKG_2), any());
+    }
+
+    @Test
+    public void snapshotThenDelete() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        int[] userIds = {12, 18};
+        rollback.snapshotUserData(PKG_2, userIds, mMockDataHelper);
+
+        verify(mMockDataHelper).snapshotAppData(eq(123), pkgRollbackInfoFor(PKG_2), eq(userIds));
+
+        rollback.delete(mMockDataHelper);
+
+        verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(12));
+        verify(mMockDataHelper).destroyAppDataSnapshot(eq(123), pkgRollbackInfoFor(PKG_2), eq(18));
+
+        assertThat(rollback.isDeleted()).isTrue();
+    }
+
+    @Test
+    public void restoreUserDataDoesNothingIfNotInProgress() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        assertThat(rollback.isRestoreUserDataInProgress()).isFalse();
+
+        assertThat(rollback.restoreUserDataForPackageIfInProgress(
+                PKG_1, new int[] { 5 }, 333, "", mMockDataHelper)).isFalse();
+
+        verify(mMockDataHelper, never()).restoreAppData(anyInt(), any(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void restoreUserDataDoesNothingIfPackageNotFound() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        rollback.setRestoreUserDataInProgress(true);
+        assertThat(rollback.isRestoreUserDataInProgress()).isTrue();
+
+        assertThat(rollback.restoreUserDataForPackageIfInProgress(
+                PKG_3, new int[] { 5 }, 333, "", mMockDataHelper)).isFalse();
+
+        verify(mMockDataHelper, never()).restoreAppData(anyInt(), any(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void restoreUserDataRestoresIfInProgressAndPackageFound() {
+        Rollback rollback = new Rollback(123, new File("/test/testing"), -1);
+        PackageRollbackInfo pkgInfo1 = newPkgInfoFor(PKG_1, 12, 10, false);
+        PackageRollbackInfo pkgInfo2 = newPkgInfoFor(PKG_2, 18, 12, true);
+        rollback.info.getPackages().addAll(Arrays.asList(pkgInfo1, pkgInfo2));
+
+        rollback.setRestoreUserDataInProgress(true);
+        assertThat(rollback.isRestoreUserDataInProgress()).isTrue();
+
+        assertThat(rollback.restoreUserDataForPackageIfInProgress(
+                PKG_1, new int[] { 5, 7 }, 333, "blah", mMockDataHelper)).isTrue();
+
+        verify(mMockDataHelper).restoreAppData(123, pkgInfo1, 5, 333, "blah");
+        verify(mMockDataHelper).restoreAppData(123, pkgInfo1, 7, 333, "blah");
+    }
+
+    private static PackageRollbackInfo newPkgInfoFor(
             String packageName, long fromVersion, long toVersion, boolean isApex) {
         return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion),
                 new VersionedPackage(packageName, toVersion),
                 new IntArray(), new ArrayList<>(), isApex, new IntArray(), new SparseLongArray());
     }
+
+    private static class PackageRollbackInfoForPackage implements
+            ArgumentMatcher<PackageRollbackInfo> {
+        private final String mPkg;
+
+        PackageRollbackInfoForPackage(String pkg) {
+            mPkg = pkg;
+        }
+
+        @Override
+        public boolean matches(PackageRollbackInfo pkgRollbackInfo) {
+            return pkgRollbackInfo.getPackageName().equals(mPkg);
+        }
+    }
+
+    private static PackageRollbackInfo pkgRollbackInfoFor(String pkg) {
+        return argThat(new PackageRollbackInfoForPackage(pkg));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
index dd2ee5c..d1ac19c 100644
--- a/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
+++ b/services/tests/servicestests/src/com/android/server/stats/ProcfsMemoryUtilTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.stats;
 
+import static com.android.server.stats.ProcfsMemoryUtil.parseCmdline;
 import static com.android.server.stats.ProcfsMemoryUtil.parseMemorySnapshotFromStatus;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +26,8 @@
 
 import org.junit.Test;
 
+import java.io.ByteArrayOutputStream;
+
 /**
  * Build/Install/Run:
  *  atest FrameworksServicesTests:ProcfsMemoryUtilTest
@@ -100,4 +103,39 @@
         MemorySnapshot snapshot = parseMemorySnapshotFromStatus("");
         assertThat(snapshot).isNull();
     }
+
+    @Test
+    public void testParseCmdline_invalidValue() {
+        byte[] nothing = new byte[] {0x00, 0x74, 0x65, 0x73, 0x74}; // \0test
+
+        assertThat(parseCmdline(bytesToString(nothing))).isEmpty();
+    }
+
+    @Test
+    public void testParseCmdline_correctValue_noNullBytes() {
+        assertThat(parseCmdline("com.google.app")).isEqualTo("com.google.app");
+    }
+
+    @Test
+    public void testParseCmdline_correctValue_withNullBytes() {
+        byte[] trailing = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00}; // test\0\0\0
+
+        assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
+
+        // test\0\0test
+        byte[] inside = new byte[] {0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74};
+
+        assertThat(parseCmdline(bytesToString(trailing))).isEqualTo("test");
+    }
+
+    @Test
+    public void testParseCmdline_emptyContents() {
+        assertThat(parseCmdline("")).isEmpty();
+    }
+
+    private static String bytesToString(byte[] bytes) {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        output.write(bytes, 0, bytes.length);
+        return output.toString();
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index dcab78e..3d87223 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -16,9 +16,10 @@
 
 package com.android.server.notification;
 
-import static junit.framework.Assert.assertEquals;
+import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertTrue;
 
 import android.app.NotificationManager.Policy;
 import android.content.ComponentName;
@@ -52,18 +53,18 @@
 
     @Test
     public void testPriorityOnlyMutingAllNotifications() {
-        ZenModeConfig config = getMutedNotificationsConfig();
-        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        ZenModeConfig config = getMutedRingerConfig();
+        assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
 
         config.allowReminders = true;
-        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
         config.allowReminders = false;
 
         config.areChannelsBypassingDnd = true;
-        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
         config.areChannelsBypassingDnd = false;
 
-        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
     }
 
     @Test
@@ -106,26 +107,26 @@
     @Test
     public void testPriorityOnlyMutingAll() {
         ZenModeConfig config = getMutedAllConfig();
-        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
-        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
 
         config.allowReminders = true;
-        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
-        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
         config.allowReminders = false;
 
         config.areChannelsBypassingDnd = true;
-        assertEquals(false, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
-        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
         config.areChannelsBypassingDnd = false;
 
         config.allowAlarms = true;
-        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
-        assertEquals(false, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+        assertFalse(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
         config.allowAlarms = false;
 
-        assertEquals(true, ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(config));
-        assertEquals(true, ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config));
+        assertTrue(ZenModeConfig.areAllZenBehaviorSoundsMuted(config));
     }
 
     @Test
@@ -200,14 +201,14 @@
         assertEquals(rule.zenMode, fromXml.zenMode);
     }
 
-    private ZenModeConfig getMutedNotificationsConfig() {
+    private ZenModeConfig getMutedRingerConfig() {
         ZenModeConfig config = new ZenModeConfig();
-        // Allow alarms, media, and system
+        // Allow alarms, media
         config.allowAlarms = true;
         config.allowMedia = true;
-        config.allowSystem = true;
 
-        // All notification sounds are not allowed
+        // All sounds that respect the ringer are not allowed
+        config.allowSystem = false;
         config.allowCalls = false;
         config.allowRepeatCallers = false;
         config.allowMessages = false;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 8936450..99771b9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -487,7 +487,6 @@
     public void testRingerAffectedStreamsPriorityOnly() {
         // in priority only mode:
         // ringtone, notification and system streams are affected by ringer mode
-        // UNLESS ringer is muted due to all the other priority only dnd sounds being muted
         mZenModeHelperSpy.mConfig.allowAlarms = true;
         mZenModeHelperSpy.mConfig.allowReminders = true;
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
@@ -503,8 +502,9 @@
         assertTrue((ringerModeAffectedStreams & (1 << AudioSystem.STREAM_ALARM)) == 0);
         assertTrue((ringerModeAffectedStreams & (1 << AudioSystem.STREAM_MUSIC)) == 0);
 
-        // special case: if ringer is muted (since all notification sounds cannot bypass)
-        // then system stream is not affected by ringer mode
+        // even when ringer is muted (since all ringer sounds cannot bypass DND),
+        // system stream is still affected by ringer mode
+        mZenModeHelperSpy.mConfig.allowSystem = false;
         mZenModeHelperSpy.mConfig.allowReminders = false;
         mZenModeHelperSpy.mConfig.allowCalls = false;
         mZenModeHelperSpy.mConfig.allowMessages = false;
@@ -519,7 +519,7 @@
         assertTrue((ringerMutedRingerModeAffectedStreams & (1 << AudioSystem.STREAM_NOTIFICATION))
                 != 0);
         assertTrue((ringerMutedRingerModeAffectedStreams & (1 << AudioSystem.STREAM_SYSTEM))
-                == 0);
+                != 0);
         assertTrue((ringerMutedRingerModeAffectedStreams & (1 << AudioSystem.STREAM_ALARM)) == 0);
         assertTrue((ringerMutedRingerModeAffectedStreams & (1 << AudioSystem.STREAM_MUSIC)) == 0);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index 6c78f6f..69cc9b2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -24,11 +24,9 @@
 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
 
@@ -49,6 +47,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.concurrent.CompletableFuture;
@@ -62,6 +61,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class ActivityDisplayTests extends ActivityTestsBase {
 
     @Test
@@ -142,30 +142,24 @@
         // Create a display which supports system decoration and allows reparenting stacks to
         // another display when the display is removed.
         final ActivityDisplay display = createNewActivityDisplay();
-        spyOn(display);
         doReturn(false).when(display).shouldDestroyContentOnRemove();
         doReturn(true).when(display).supportsSystemDecorations();
         mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP);
 
         // Put home stack on the display.
-        final ActivityStack homeStack = display.createStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(homeStack).build();
-        new ActivityBuilder(mService).setTask(task).build();
-        display.removeChild(homeStack);
-        final ActivityStack spiedHomeStack = spy(homeStack);
-        display.addChild(spiedHomeStack, ActivityDisplay.POSITION_TOP);
-        reset(spiedHomeStack);
+        final ActivityStack homeStack = new StackBuilder(mRootActivityContainer)
+                .setDisplay(display).setActivityType(ACTIVITY_TYPE_HOME).build();
 
         // Put a finishing standard activity which will be reparented.
         final ActivityStack stack = createFullscreenStackWithSimpleActivityAt(display);
         stack.topRunningActivityLocked().makeFinishingLocked();
 
+        clearInvocations(homeStack);
         display.remove();
 
         // The removed display should have no focused stack and its home stack should never resume.
         assertNull(display.getFocusedStack());
-        verify(spiedHomeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
+        verify(homeStack, never()).resumeTopActivityUncheckedLocked(any(), any());
     }
 
     private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
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 30c8eb3..50203df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -103,8 +103,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.invocation.InvocationOnMock;
 
-import java.util.concurrent.TimeUnit;
-
 /**
  * Tests for the {@link ActivityRecord} class.
  *
@@ -646,7 +644,7 @@
         // The override configuration should be reset and the activity's process will be killed.
         assertFalse(mActivity.inSizeCompatMode());
         verify(mActivity).restartProcessIfVisible();
-        mLockRule.runWithScissors(mService.mH, () -> { }, TimeUnit.SECONDS.toMillis(3));
+        waitHandlerIdle(mService.mH);
         verify(mService.mAmInternal).killProcess(
                 eq(mActivity.app.mName), eq(mActivity.app.mUid), anyString());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 9583b8ac..9e1df91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -44,6 +44,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link ActivityStackSupervisor} class.
@@ -53,6 +54,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class ActivityStackSupervisorTests extends ActivityTestsBase {
     private ActivityStack mFullscreenStack;
 
@@ -79,32 +81,28 @@
     /**
      * Ensures that waiting results are notified of launches.
      */
-    @SuppressWarnings("SynchronizeOnNonFinalField")
     @Test
     public void testReportWaitingActivityLaunchedIfNeeded() {
         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
 
-        // #notifyAll will be called on the ActivityManagerService. we must hold the object lock
-        // when this happens.
-        synchronized (mService.mGlobalLock) {
-            final WaitResult taskToFrontWait = new WaitResult();
-            mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
-            mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT);
+        final WaitResult taskToFrontWait = new WaitResult();
+        mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
+        // #notifyAll will be called on the ActivityTaskManagerService#mGlobalLock. The lock is hold
+        // implicitly by WindowManagerGlobalLockRule.
+        mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT);
 
-            assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
-            assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
-            assertNull(taskToFrontWait.who);
+        assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
+        assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
+        assertNull(taskToFrontWait.who);
 
-            final WaitResult deliverToTopWait = new WaitResult();
-            mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait);
-            mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity,
-                    START_DELIVERED_TO_TOP);
+        final WaitResult deliverToTopWait = new WaitResult();
+        mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait);
+        mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_DELIVERED_TO_TOP);
 
-            assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
-            assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP);
-            assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent);
-        }
+        assertThat(mSupervisor.mWaitingActivityLaunched).isEmpty();
+        assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP);
+        assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent);
     }
 
     /**
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 2a8b4c8..c2a05c24 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -67,6 +67,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link ActivityStack} class.
@@ -76,6 +77,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class ActivityStackTests extends ActivityTestsBase {
     private ActivityDisplay mDefaultDisplay;
     private ActivityStack mStack;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index a7bbe6e..5e4c9658 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -38,6 +38,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.Random;
 
@@ -49,6 +50,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class ActivityStartControllerTests extends ActivityTestsBase {
     private ActivityStartController mController;
     private Factory mFactory;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 350114c..4165052 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -175,8 +175,8 @@
                 .build();
         when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
                 .thenReturn(suspendingPackage);
-        when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, TEST_USER_ID))
-                .thenReturn(dialogInfo);
+        when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
+                TEST_USER_ID)).thenReturn(dialogInfo);
         // THEN calling intercept returns true
         assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
 
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 1f672c0..78f3f79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -753,7 +753,7 @@
                 false /* mockGetLaunchStack */);
 
         // Create a secondary display at bottom.
-        final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+        final TestActivityDisplay secondaryDisplay = createNewActivityDisplay();
         mRootActivityContainer.addChild(secondaryDisplay, POSITION_BOTTOM);
         final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -791,7 +791,7 @@
                 false /* mockGetLaunchStack */);
 
         // Create a secondary display with an activity.
-        final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
+        final TestActivityDisplay secondaryDisplay = createNewActivityDisplay();
         mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
         final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
                 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 297aa7e..7b7e6e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -26,6 +26,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link ActivityTaskManagerService} class.
@@ -34,6 +35,7 @@
  *  atest WmTests:ActivityTaskManagerServiceTests
  */
 @MediumTest
+@RunWith(WindowTestRunner.class)
 public class ActivityTaskManagerServiceTests extends ActivityTestsBase {
 
     @Before
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index d311dfc..f4d1cbf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -40,31 +40,17 @@
 import android.content.res.Configuration;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
-import android.testing.DexmakerShareClassLoaderRule;
 import android.view.DisplayInfo;
 
 import com.android.server.AttributeCache;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Rule;
 
 /**
  * A base class to handle common operations in activity related unit tests.
  */
-class ActivityTestsBase {
-
-    @Rule
-    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
-            new DexmakerShareClassLoaderRule();
-
-    @Rule
-    public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
-
-    @WindowTestRunner.MethodWrapperRule
-    public final WindowManagerGlobalLockRule mLockRule =
-            new WindowManagerGlobalLockRule(mSystemServicesTestRule);
-
+class ActivityTestsBase extends SystemServiceTestsBase {
     final Context mContext = getInstrumentation().getTargetContext();
 
     ActivityTaskManagerService mService;
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 629a954..61dbd67 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -42,6 +42,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for change transitions
@@ -51,6 +52,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppChangeTransitionTests extends WindowTestsBase {
 
     private TaskStack mStack;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index e71c8f4..605d520 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -36,6 +36,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Build/Install/Run:
@@ -43,6 +44,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppTransitionControllerTest extends WindowTestsBase {
 
     private AppTransitionController mAppTransitionController;
@@ -55,73 +57,63 @@
     @Test
     @FlakyTest(bugId = 131005232)
     public void testTranslucentOpen() {
-        synchronized (mWm.mGlobalLock) {
-            final AppWindowToken behind = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentOpening.setOccludesParent(false);
-            translucentOpening.setHidden(true);
-            mDisplayContent.mOpeningApps.add(behind);
-            mDisplayContent.mOpeningApps.add(translucentOpening);
-            assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
-                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
-                            TRANSIT_TASK_OPEN));
-        }
+        final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        translucentOpening.setOccludesParent(false);
+        translucentOpening.setHidden(true);
+        mDisplayContent.mOpeningApps.add(behind);
+        mDisplayContent.mOpeningApps.add(translucentOpening);
+        assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
+                mAppTransitionController.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_OPEN));
     }
 
     @Test
     @FlakyTest(bugId = 131005232)
     public void testTranslucentClose() {
-        synchronized (mWm.mGlobalLock) {
-            final AppWindowToken behind = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentClosing.setOccludesParent(false);
-            mDisplayContent.mClosingApps.add(translucentClosing);
-            assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
-                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
-                            TRANSIT_TASK_CLOSE));
-        }
+        final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        translucentClosing.setOccludesParent(false);
+        mDisplayContent.mClosingApps.add(translucentClosing);
+        assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
+                mAppTransitionController.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_CLOSE));
     }
 
     @Test
     @FlakyTest(bugId = 131005232)
     public void testChangeIsNotOverwritten() {
-        synchronized (mWm.mGlobalLock) {
-            final AppWindowToken behind = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-            translucentOpening.setOccludesParent(false);
-            translucentOpening.setHidden(true);
-            mDisplayContent.mOpeningApps.add(behind);
-            mDisplayContent.mOpeningApps.add(translucentOpening);
-            assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
-                    mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
-                            TRANSIT_TASK_CHANGE_WINDOWING_MODE));
-        }
+        final AppWindowToken behind = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        final AppWindowToken translucentOpening = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+        translucentOpening.setOccludesParent(false);
+        translucentOpening.setHidden(true);
+        mDisplayContent.mOpeningApps.add(behind);
+        mDisplayContent.mOpeningApps.add(translucentOpening);
+        assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
+                mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+                        TRANSIT_TASK_CHANGE_WINDOWING_MODE));
     }
 
     @Test
     @FlakyTest(bugId = 131005232)
     public void testTransitWithinTask() {
-        synchronized (mWm.mGlobalLock) {
-            final AppWindowToken opening = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
-            opening.setOccludesParent(false);
-            final AppWindowToken closing = createAppWindowToken(mDisplayContent,
-                    WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
-            closing.setOccludesParent(false);
-            Task task = opening.getTask();
-            mDisplayContent.mOpeningApps.add(opening);
-            mDisplayContent.mClosingApps.add(closing);
-            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
-            closing.getTask().removeChild(closing);
-            task.addChild(closing, 0);
-            assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
-            assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task));
-        }
+        final AppWindowToken opening = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+        opening.setOccludesParent(false);
+        final AppWindowToken closing = createAppWindowToken(mDisplayContent,
+                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+        closing.setOccludesParent(false);
+        final Task task = opening.getTask();
+        mDisplayContent.mOpeningApps.add(opening);
+        mDisplayContent.mClosingApps.add(closing);
+        assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+        closing.getTask().removeChild(closing);
+        task.addChild(closing, 0);
+        assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+        assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task));
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 45e6890..49e4c78 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -31,7 +31,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -55,6 +54,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link AppTransition}.
@@ -64,16 +64,13 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppTransitionTests extends WindowTestsBase {
     private DisplayContent mDc;
 
     @Before
     public void setUp() throws Exception {
-        synchronized (mWm.mGlobalLock) {
-            // Hold the lock to protect the stubbing from being accessed by other threads.
-            spyOn(mWm.mRoot);
-            doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
-        }
+        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
         mDc = mWm.getDefaultDisplayContentLocked();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
index b8f8e21..aacdeb2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowThumbnailTest.java
@@ -17,8 +17,8 @@
 package com.android.server.wm;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
@@ -26,12 +26,12 @@
 import android.graphics.PixelFormat;
 import android.platform.test.annotations.Presubmit;
 import android.view.Surface;
-import android.view.SurfaceControl;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link TaskSnapshotSurface}.
@@ -42,6 +42,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppWindowThumbnailTest extends WindowTestsBase {
     private AppWindowThumbnail buildThumbnail() {
         final GraphicBuffer buffer = GraphicBuffer.create(1, 1, PixelFormat.RGBA_8888,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index 70d9b5f..8957486 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -37,6 +37,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -50,6 +51,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppWindowTokenAnimationTests extends WindowTestsBase {
 
     private TestAppWindowToken mToken;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 1f634b1..d528e41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -62,6 +62,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
 /**
@@ -72,6 +73,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class AppWindowTokenTests extends WindowTestsBase {
 
     TaskStack mStack;
@@ -324,40 +326,36 @@
 
     @Test
     public void testReportOrientationChangeOnVisibilityChange() {
-        synchronized (mWm.mGlobalLock) {
-            mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
-            mDisplayContent.getDisplayRotation().setFixedToUserRotation(
-                    DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
+        mDisplayContent.getDisplayRotation().setFixedToUserRotation(
+                DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
 
-            doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord)
-                    .getRequestedConfigurationOrientation();
+        doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord)
+                .getRequestedConfigurationOrientation();
 
-            mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
-            mToken.commitVisibility(null, false /* visible */, TRANSIT_UNSET,
-                    true /* performLayout */, false /* isVoiceInteraction */);
-        }
+        mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
+        mToken.commitVisibility(null /* lp */, false /* visible */, TRANSIT_UNSET,
+                true /* performLayout */, false /* isVoiceInteraction */);
 
         verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class));
     }
 
     @Test
     public void testReportOrientationChangeOnOpeningClosingAppChange() {
-        synchronized (mWm.mGlobalLock) {
-            mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        mToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
 
-            mDisplayContent.getDisplayRotation().setFixedToUserRotation(
-                    DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
-            mDisplayContent.getDisplayInfo().state = Display.STATE_ON;
-            mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_CLOSE,
-                    false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+        mDisplayContent.getDisplayRotation().setFixedToUserRotation(
+                DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED);
+        mDisplayContent.getDisplayInfo().state = Display.STATE_ON;
+        mDisplayContent.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_CLOSE,
+                false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
 
-            doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord)
-                    .getRequestedConfigurationOrientation();
+        doReturn(Configuration.ORIENTATION_LANDSCAPE).when(mToken.mActivityRecord)
+                .getRequestedConfigurationOrientation();
 
-            mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
-            mToken.setVisibility(false, false);
-        }
+        mTask.mTaskRecord = Mockito.mock(TaskRecord.class, RETURNS_DEEP_STUBS);
+        mToken.setVisibility(false /* visible */, false /* deferHidingClient */);
 
         verify(mTask.mTaskRecord).onConfigurationChanged(any(Configuration.class));
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index bb574ce..2e85897 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -22,6 +22,8 @@
 import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
 import static android.graphics.Bitmap.Config.ARGB_8888;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -71,7 +73,7 @@
  */
 @MediumTest
 @Presubmit
-public class AssistDataRequesterTest extends ActivityTestsBase {
+public class AssistDataRequesterTest {
 
     private static final String TAG = AssistDataRequesterTest.class.getSimpleName();
 
@@ -111,8 +113,9 @@
         mHandler = new Handler(Looper.getMainLooper());
         mCallbacksLock = new Object();
         mCallbacks = new Callbacks();
-        mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
-                mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
+        mDataRequester = new AssistDataRequester(getInstrumentation().getTargetContext(), mWm,
+                mAppOpsManager, mCallbacks, mCallbacksLock, OP_ASSIST_STRUCTURE,
+                OP_ASSIST_SCREENSHOT);
         mDataRequester.mActivityTaskManager = mAtm;
         // Gate the continuation of the assist data callbacks until we are ready within the tests
         mGate = new CountDownLatch(1);
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 44f3ee41..ade0b14 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -39,6 +39,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
@@ -46,8 +47,8 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -72,7 +73,6 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
-import android.util.MutableBoolean;
 import android.view.DisplayCutout;
 import android.view.Gravity;
 import android.view.ISystemGestureExclusionListener;
@@ -88,6 +88,7 @@
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
@@ -105,6 +106,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DisplayContentTests extends WindowTestsBase {
 
     @Test
@@ -396,6 +398,59 @@
                 mWm.mRoot.getTopFocusedDisplayContent().getDisplayId());
     }
 
+    @Test
+    public void testShouldWaitForSystemDecorWindowsOnBoot_OnDefaultDisplay() {
+        mWm.mSystemBooted = true;
+        final DisplayContent defaultDisplay = mWm.getDefaultDisplayContentLocked();
+        final WindowState[] windows = createNotDrawnWindowsOn(defaultDisplay,
+                TYPE_WALLPAPER, TYPE_APPLICATION);
+
+        // Verify waiting for windows to be drawn.
+        assertTrue(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot());
+
+        // Verify not waiting for drawn windows.
+        makeWindowsDrawn(windows);
+        assertFalse(defaultDisplay.shouldWaitForSystemDecorWindowsOnBoot());
+    }
+
+    @Test
+    public void testShouldWaitForSystemDecorWindowsOnBoot_OnSecondaryDisplay() {
+        mWm.mSystemBooted = true;
+        final DisplayContent secondaryDisplay = createNewDisplay();
+        final WindowState[] windows = createNotDrawnWindowsOn(secondaryDisplay,
+                TYPE_WALLPAPER, TYPE_APPLICATION);
+
+        // Verify not waiting for display without system decorations.
+        doReturn(false).when(secondaryDisplay).supportsSystemDecorations();
+        assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
+
+        // Verify waiting for non-drawn windows on display with system decorations.
+        reset(secondaryDisplay);
+        doReturn(true).when(secondaryDisplay).supportsSystemDecorations();
+        assertTrue(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
+
+        // Verify not waiting for drawn windows on display with system decorations.
+        makeWindowsDrawn(windows);
+        assertFalse(secondaryDisplay.shouldWaitForSystemDecorWindowsOnBoot());
+    }
+
+    private WindowState[] createNotDrawnWindowsOn(DisplayContent displayContent, int... types) {
+        final WindowState[] windows = new WindowState[types.length];
+        for (int i = 0; i < types.length; i++) {
+            final int type = types[i];
+            windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type);
+            windows[i].mHasSurface = false;
+        }
+        return windows;
+    }
+
+    private static void makeWindowsDrawn(WindowState[] windows) {
+        for (WindowState window : windows) {
+            window.mHasSurface = true;
+            window.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN;
+        }
+    }
+
     /**
      * This tests setting the maximum ui width on a display.
      */
@@ -435,78 +490,70 @@
 
     @Test
     public void testDisplayCutout_rot0() {
-        synchronized (mWm.getWindowManagerLock()) {
-            final DisplayContent dc = createNewDisplay();
-            dc.mInitialDisplayWidth = 200;
-            dc.mInitialDisplayHeight = 400;
-            Rect r = new Rect(80, 0, 120, 10);
-            final DisplayCutout cutout = new WmDisplayCutout(
-                    fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
-                    .computeSafeInsets(200, 400).getDisplayCutout();
+        final DisplayContent dc = createNewDisplay();
+        dc.mInitialDisplayWidth = 200;
+        dc.mInitialDisplayHeight = 400;
+        final Rect r = new Rect(80, 0, 120, 10);
+        final DisplayCutout cutout = new WmDisplayCutout(
+                fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_TOP), null)
+                        .computeSafeInsets(200, 400).getDisplayCutout();
 
-            dc.mInitialDisplayCutout = cutout;
-            dc.getDisplayRotation().setRotation(Surface.ROTATION_0);
-            dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+        dc.mInitialDisplayCutout = cutout;
+        dc.getDisplayRotation().setRotation(Surface.ROTATION_0);
+        dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
 
-            assertEquals(cutout, dc.getDisplayInfo().displayCutout);
-        }
+        assertEquals(cutout, dc.getDisplayInfo().displayCutout);
     }
 
     @Test
     public void testDisplayCutout_rot90() {
-        synchronized (mWm.getWindowManagerLock()) {
-            // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
-            // if the device has no cutout).
-            final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
-            // Rotation may use real display info to compute bound, so here also uses the
-            // same width and height.
-            final int displayWidth = dc.mInitialDisplayWidth;
-            final int displayHeight = dc.mInitialDisplayHeight;
-            final int cutoutWidth = 40;
-            final int cutoutHeight = 10;
-            final int left = (displayWidth - cutoutWidth) / 2;
-            final int top = 0;
-            final int right = (displayWidth + cutoutWidth) / 2;
-            final int bottom = cutoutHeight;
+        // Prevent mInitialDisplayCutout from being updated from real display (e.g. null
+        // if the device has no cutout).
+        final DisplayContent dc = createDisplayNoUpdateDisplayInfo();
+        // Rotation may use real display info to compute bound, so here also uses the
+        // same width and height.
+        final int displayWidth = dc.mInitialDisplayWidth;
+        final int displayHeight = dc.mInitialDisplayHeight;
+        final int cutoutWidth = 40;
+        final int cutoutHeight = 10;
+        final int left = (displayWidth - cutoutWidth) / 2;
+        final int top = 0;
+        final int right = (displayWidth + cutoutWidth) / 2;
+        final int bottom = cutoutHeight;
 
-            final Rect r1 = new Rect(left, top, right, bottom);
-            final DisplayCutout cutout = new WmDisplayCutout(
-                    fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP),
-                    null)
-                    .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
+        final Rect r1 = new Rect(left, top, right, bottom);
+        final DisplayCutout cutout = new WmDisplayCutout(
+                fromBoundingRect(r1.left, r1.top, r1.right, r1.bottom, BOUNDS_POSITION_TOP), null)
+                        .computeSafeInsets(displayWidth, displayHeight).getDisplayCutout();
 
-            dc.mInitialDisplayCutout = cutout;
-            dc.getDisplayRotation().setRotation(Surface.ROTATION_90);
-            dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
+        dc.mInitialDisplayCutout = cutout;
+        dc.getDisplayRotation().setRotation(Surface.ROTATION_90);
+        dc.computeScreenConfiguration(new Configuration()); // recomputes dc.mDisplayInfo.
 
-            // ----o----------      -------------
-            // |   |     |   |      |
-            // |   ------o   |      o---
-            // |             |      |  |
-            // |             |  ->  |  |
-            // |             |      ---o
-            // |             |      |
-            // |             |      -------------
-            final Rect r = new Rect(top, left, bottom, right);
-            assertEquals(new WmDisplayCutout(
-                    fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
-                    .computeSafeInsets(displayHeight, displayWidth)
-                    .getDisplayCutout(), dc.getDisplayInfo().displayCutout);
-        }
+        // ----o----------      -------------
+        // |   |     |   |      |
+        // |   ------o   |      o---
+        // |             |      |  |
+        // |             |  ->  |  |
+        // |             |      ---o
+        // |             |      |
+        // |             |      -------------
+        final Rect r = new Rect(top, left, bottom, right);
+        assertEquals(new WmDisplayCutout(
+                fromBoundingRect(r.left, r.top, r.right, r.bottom, BOUNDS_POSITION_LEFT), null)
+                        .computeSafeInsets(displayHeight, displayWidth).getDisplayCutout(),
+                dc.getDisplayInfo().displayCutout);
     }
 
     @Test
     public void testLayoutSeq_assignedDuringLayout() {
-        synchronized (mWm.getWindowManagerLock()) {
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
 
-            final DisplayContent dc = createNewDisplay();
-            final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+        dc.setLayoutNeeded();
+        dc.performLayout(true /* initial */, false /* updateImeWindows */);
 
-            dc.setLayoutNeeded();
-            dc.performLayout(true /* initial */, false /* updateImeWindows */);
-
-            assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
-        }
+        assertThat(win.mLayoutSeq, is(dc.mLayoutSeq));
     }
 
     @Test
@@ -751,7 +798,7 @@
         win.setHasSurface(true);
         dc.updateSystemGestureExclusion();
 
-        final MutableBoolean invoked = new MutableBoolean(false);
+        final boolean[] invoked = { false };
         final ISystemGestureExclusionListener.Stub verifier =
                 new ISystemGestureExclusionListener.Stub() {
             @Override
@@ -760,7 +807,7 @@
                 Region expected = Region.obtain();
                 expected.set(10, 20, 30, 40);
                 assertEquals(expected, actual);
-                invoked.value = true;
+                invoked[0] = true;
             }
         };
         try {
@@ -768,7 +815,7 @@
         } finally {
             dc.unregisterSystemGestureExclusionListener(verifier);
         }
-        assertTrue("SystemGestureExclusionListener was not invoked", invoked.value);
+        assertTrue("SystemGestureExclusionListener was not invoked", invoked[0]);
     }
 
     @Test
@@ -826,30 +873,28 @@
 
     @Test
     public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
-        synchronized (mWm.mGlobalLock) {
-            mWm.mSystemGestureExcludedByPreQStickyImmersive = true;
+        mWm.mSystemGestureExcludedByPreQStickyImmersive = true;
 
-            final DisplayContent dc = createNewDisplay();
-            final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
-            win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
-            win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-            win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
-            win.getAttrs().subtreeSystemUiVisibility = win.mSystemUiVisibility =
-                    SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION
-                            | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
-            win.mAppToken.mTargetSdk = P;
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+        win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+        win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+        win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+        win.getAttrs().subtreeSystemUiVisibility = win.mSystemUiVisibility =
+                SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                        | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+        win.mAppToken.mTargetSdk = P;
 
-            dc.setLayoutNeeded();
-            dc.performLayout(true /* initial */, false /* updateImeWindows */);
+        dc.setLayoutNeeded();
+        dc.performLayout(true /* initial */, false /* updateImeWindows */);
 
-            win.setHasSurface(true);
+        win.setHasSurface(true);
 
-            final Region expected = Region.obtain();
-            expected.set(dc.getBounds());
-            assertEquals(expected, calculateSystemGestureExclusion(dc));
+        final Region expected = Region.obtain();
+        expected.set(dc.getBounds());
+        assertEquals(expected, calculateSystemGestureExclusion(dc));
 
-            win.setHasSurface(false);
-        }
+        win.setHasSurface(false);
     }
 
     @Test
@@ -860,7 +905,7 @@
 
         Configuration newConfig = new Configuration();
         newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
-        final DisplayContent displayContent = spy(createNewDisplay());
+        final DisplayContent displayContent = createNewDisplay();
         Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger();
         Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration();
 
@@ -886,9 +931,7 @@
     }
 
     private void updateFocusedWindow() {
-        synchronized (mWm.mGlobalLock) {
-            mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false);
-        }
+        mWm.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, false /* updateInputWindows */);
     }
 
     /**
@@ -896,7 +939,7 @@
      * the values set by test.
      */
     private DisplayContent createDisplayNoUpdateDisplayInfo() {
-        final DisplayContent displayContent = spy(createNewDisplay());
+        final DisplayContent displayContent = createNewDisplay();
         doNothing().when(displayContent).updateDisplayInfo();
         return displayContent;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index de184b8..2a3731a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -63,9 +63,11 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
 
     private DisplayFrames mFrames;
@@ -118,458 +120,415 @@
 
     @Test
     public void layoutWindowLw_appDrawsBars() {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            addWindow(mWindow);
+        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_appWontDrawBars() {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            addWindow(mWindow);
+        mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
     }
 
     @Test
     public void layoutWindowLw_appWontDrawBars_forceStatusAndNav() throws Exception {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-            addWindow(mWindow);
+        mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
     @Test
     public void layoutWindowLw_keyguardDialog_hideNav() {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
-            mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-            addWindow(mWindow);
+        mWindow.mAttrs.type = TYPE_KEYGUARD_DIALOG;
+        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mAttrs.systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* uiMode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null /* attached */, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            addWindow(mWindow);
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_never() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-            addWindow(mWindow);
+        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            addWindow(mWindow);
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_fullscreen() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
-            addWindow(mWindow);
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
-            mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-            addWindow(mWindow);
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
     }
 
 
     @Test
     public void layoutWindowLw_withDisplayCutout_landscape() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
-            setRotation(ROTATION_90);
-            addWindow(mWindow);
+        addDisplayCutout();
+        setRotation(ROTATION_90);
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-            assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getContentFrameLw(),
-                    DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrameLw(),
+                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_seascape() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
-            setRotation(ROTATION_270);
-            addWindow(mWindow);
+        addDisplayCutout();
+        setRotation(ROTATION_270);
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
-            assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
-            assertInsetBy(mWindow.getContentFrameLw(),
-                    NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+        assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+        assertInsetBy(mWindow.getContentFrameLw(),
+                NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
-            setRotation(ROTATION_90);
+        addDisplayCutout();
+        setRotation(ROTATION_90);
 
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            addWindow(mWindow);
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
-            assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getContentFrameLw(),
-                    DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrameLw(),
+                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
+        addDisplayCutout();
 
-            mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
-            mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
-            mWindow.mAttrs.width = DISPLAY_WIDTH;
-            mWindow.mAttrs.height = DISPLAY_HEIGHT;
-            addWindow(mWindow);
+        mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
+        mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
+        mWindow.mAttrs.width = DISPLAY_WIDTH;
+        mWindow.mAttrs.height = DISPLAY_HEIGHT;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        }
+        assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
     }
 
     @Test
     public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
-        synchronized (mWm.mGlobalLock) {
-            addDisplayCutout();
-            setRotation(ROTATION_90);
+        addDisplayCutout();
+        setRotation(ROTATION_90);
 
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-            addWindow(mWindow);
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-            assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getContentFrameLw(),
-                    DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getContentFrameLw(),
+                DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
-            addWindow(mWindow);
+        mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+        addWindow(mWindow);
 
-            final int forwardedInsetBottom = 50;
-            mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        final int forwardedInsetBottom = 50;
+        mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(),
-                    STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
-            assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
-                    STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(),
+                STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
+                STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
-        synchronized (mWm.mGlobalLock) {
-            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
-            addWindow(mWindow);
+        mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
+        addWindow(mWindow);
 
-            final int forwardedInsetBottom = 50;
-            mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        final int forwardedInsetBottom = 50;
+        mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
 
-            assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
-            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
-            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
-        }
+        assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+        assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+        assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+        assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
     }
 
     @Test
     public void layoutHint_appWindow() {
-        synchronized (mWm.mGlobalLock) {
-            // Initialize DisplayFrames
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        // Initialize DisplayFrames
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
-            final Rect outFrame = new Rect();
-            final Rect outContentInsets = new Rect();
-            final Rect outStableInsets = new Rect();
-            final Rect outOutsets = new Rect();
-            final DisplayCutout.ParcelableWrapper outDisplayCutout =
-                    new DisplayCutout.ParcelableWrapper();
+        final Rect outFrame = new Rect();
+        final Rect outContentInsets = new Rect();
+        final Rect outStableInsets = new Rect();
+        final Rect outOutsets = new Rect();
+        final DisplayCutout.ParcelableWrapper outDisplayCutout =
+                new DisplayCutout.ParcelableWrapper();
 
-            mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
-                    false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                    outOutsets, outDisplayCutout);
+        mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
+                false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
+                outOutsets, outDisplayCutout);
 
-            assertThat(outFrame, is(mFrames.mUnrestricted));
-            assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
-            assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
-            assertThat(outOutsets, is(new Rect()));
-            assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
-        }
+        assertThat(outFrame, is(mFrames.mUnrestricted));
+        assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+        assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+        assertThat(outOutsets, is(new Rect()));
+        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
     @Test
     public void layoutHint_appWindowInTask() {
-        synchronized (mWm.mGlobalLock) {
-            // Initialize DisplayFrames
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        // Initialize DisplayFrames
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
-            final Rect taskBounds = new Rect(100, 100, 200, 200);
+        final Rect taskBounds = new Rect(100, 100, 200, 200);
 
-            final Rect outFrame = new Rect();
-            final Rect outContentInsets = new Rect();
-            final Rect outStableInsets = new Rect();
-            final Rect outOutsets = new Rect();
-            final DisplayCutout.ParcelableWrapper outDisplayCutout =
-                    new DisplayCutout.ParcelableWrapper();
+        final Rect outFrame = new Rect();
+        final Rect outContentInsets = new Rect();
+        final Rect outStableInsets = new Rect();
+        final Rect outOutsets = new Rect();
+        final DisplayCutout.ParcelableWrapper outDisplayCutout =
+                new DisplayCutout.ParcelableWrapper();
 
-            mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
-                    false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                    outOutsets, outDisplayCutout);
+        mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
+                false /* floatingStack */, outFrame, outContentInsets, outStableInsets,
+                outOutsets, outDisplayCutout);
 
-            assertThat(outFrame, is(taskBounds));
-            assertThat(outContentInsets, is(new Rect()));
-            assertThat(outStableInsets, is(new Rect()));
-            assertThat(outOutsets, is(new Rect()));
-            assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
-        }
+        assertThat(outFrame, is(taskBounds));
+        assertThat(outContentInsets, is(new Rect()));
+        assertThat(outStableInsets, is(new Rect()));
+        assertThat(outOutsets, is(new Rect()));
+        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
     @Test
     public void layoutHint_appWindowInTask_outsideContentFrame() {
-        synchronized (mWm.mGlobalLock) {
-            // Initialize DisplayFrames
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        // Initialize DisplayFrames
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
 
-            // Task is in the nav bar area (usually does not happen, but this is similar enough to
-            // the possible overlap with the IME)
-            final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1,
-                    200, mFrames.mContent.bottom + 10);
+        // Task is in the nav bar area (usually does not happen, but this is similar enough to
+        // the possible overlap with the IME)
+        final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1,
+                200, mFrames.mContent.bottom + 10);
 
-            final Rect outFrame = new Rect();
-            final Rect outContentInsets = new Rect();
-            final Rect outStableInsets = new Rect();
-            final Rect outOutsets = new Rect();
-            final DisplayCutout.ParcelableWrapper outDisplayCutout =
-                    new DisplayCutout.ParcelableWrapper();
+        final Rect outFrame = new Rect();
+        final Rect outContentInsets = new Rect();
+        final Rect outStableInsets = new Rect();
+        final Rect outOutsets = new Rect();
+        final DisplayCutout.ParcelableWrapper outDisplayCutout =
+                new DisplayCutout.ParcelableWrapper();
 
-            mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
-                    true /* floatingStack */, outFrame, outContentInsets, outStableInsets,
-                    outOutsets, outDisplayCutout);
+        mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
+                true /* floatingStack */, outFrame, outContentInsets, outStableInsets,
+                outOutsets, outDisplayCutout);
 
-            assertThat(outFrame, is(taskBounds));
-            assertThat(outContentInsets, is(new Rect()));
-            assertThat(outStableInsets, is(new Rect()));
-            assertThat(outOutsets, is(new Rect()));
-            assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
-        }
+        assertThat(outFrame, is(taskBounds));
+        assertThat(outContentInsets, is(new Rect()));
+        assertThat(outStableInsets, is(new Rect()));
+        assertThat(outOutsets, is(new Rect()));
+        assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
     }
 
     @Test
     public void forceShowSystemBars_clearsSystemUIFlags() {
-        synchronized (mWm.mGlobalLock) {
-            mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
-            mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
-            mDisplayPolicy.setForceShowSystemBars(true);
-            addWindow(mWindow);
+        mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
+        mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+        mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        mWindow.mSystemUiVisibility = SYSTEM_UI_FLAG_FULLSCREEN;
+        mDisplayPolicy.setForceShowSystemBars(true);
+        addWindow(mWindow);
 
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            // triggers updateSystemUiVisibilityLw which will reset the flags as needed
-            int finishPostLayoutPolicyLw = mDisplayPolicy.focusChangedLw(mWindow, mWindow);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        // triggers updateSystemUiVisibilityLw which will reset the flags as needed
+        int finishPostLayoutPolicyLw = mDisplayPolicy.focusChangedLw(mWindow, mWindow);
 
-            assertEquals(WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT, finishPostLayoutPolicyLw);
-            assertEquals(0, mDisplayPolicy.mLastSystemUiFlags);
-            assertEquals(0, mWindow.mAttrs.systemUiVisibility);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        }
+        assertEquals(WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT, finishPostLayoutPolicyLw);
+        assertEquals(0, mDisplayPolicy.mLastSystemUiFlags);
+        assertEquals(0, mWindow.mAttrs.systemUiVisibility);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
     }
 
     @Test
     public void testScreenDecorWindows() {
-        synchronized (mWm.mGlobalLock) {
-            final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY,
-                    "decorWindow");
-            decorWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
-            decorWindow.mAttrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
-            addWindow(decorWindow);
-            addWindow(mWindow);
+        final WindowState decorWindow = createWindow(null, TYPE_APPLICATION_OVERLAY, "decorWindow");
+        decorWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+        decorWindow.mAttrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
+        addWindow(decorWindow);
+        addWindow(mWindow);
 
-            // Decor on top
-            updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
+        // Decor on top
+        updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, TOP);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, NAV_BAR_HEIGHT);
 
-            // Decor on bottom
-            updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
-                    DECOR_WINDOW_INSET);
+        // Decor on bottom
+        updateDecorWindow(decorWindow, MATCH_PARENT, DECOR_WINDOW_INSET, BOTTOM);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT,
+                DECOR_WINDOW_INSET);
 
-            // Decor on the left
-            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
-                    NAV_BAR_HEIGHT);
+        // Decor on the left
+        updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, LEFT);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        assertInsetBy(mWindow.getContentFrameLw(), DECOR_WINDOW_INSET, STATUS_BAR_HEIGHT, 0,
+                NAV_BAR_HEIGHT);
 
-            // Decor on the right
-            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
-                    NAV_BAR_HEIGHT);
+        // Decor on the right
+        updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, MATCH_PARENT, RIGHT);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        assertInsetBy(mWindow.getContentFrameLw(), 0, STATUS_BAR_HEIGHT, DECOR_WINDOW_INSET,
+                NAV_BAR_HEIGHT);
 
-            // Decor not allowed as inset
-            updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
-            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
-            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
-        }
+        // Decor not allowed as inset
+        updateDecorWindow(decorWindow, DECOR_WINDOW_INSET, DECOR_WINDOW_INSET, TOP);
+        mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+        mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+        assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
     }
 
     private void updateDecorWindow(WindowState decorWindow, int width, int height, int gravity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 3ead9779..e699b52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -54,9 +54,11 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DisplayPolicyTests extends WindowTestsBase {
 
     private WindowState createOpaqueFullscreen(boolean hasLightNavBar) {
@@ -225,13 +227,10 @@
         final WindowState activity = createApplicationWindow();
         final WindowState toast = createToastWindow();
 
-        synchronized (mWm.mGlobalLock) {
-            policy.adjustWindowParamsLw(
-                    toast, toast.mAttrs, 0 /* callingPid */, 0 /* callingUid */);
+        policy.adjustWindowParamsLw(toast, toast.mAttrs, 0 /* callingPid */, 0 /* callingUid */);
 
-            assertTrue(policy.canToastShowWhenLocked(0 /* callingUid */));
-            assertNotEquals(0, toast.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED);
-        }
+        assertTrue(policy.canToastShowWhenLocked(0 /* callingUid */));
+        assertNotEquals(0, toast.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED);
     }
 
     private WindowState createToastWindow() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 059ff3d..480c468 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -68,6 +68,7 @@
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -122,6 +123,12 @@
         sMockWm.mPolicy = mock(WindowManagerPolicy.class);
     }
 
+    @AfterClass
+    public static void tearDownOnce() {
+        // Make sure the fake settings are cleared after the last test method.
+        FakeSettingsProvider.clearSettingsProvider();
+    }
+
     @Before
     public void setUp() {
         FakeSettingsProvider.clearSettingsProvider();
@@ -238,15 +245,55 @@
     }
 
     @Test
-    public void testReturnsUserRotation_UserRotationLocked_CompatibleAppRequest()
+    public void testReturnsLandscape_UserRotationLockedSeascape_AppRequestsLandscape()
             throws Exception {
         mBuilder.build();
-        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false, false);
+        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
+                false /* isTv */);
+
+        freezeRotation(Surface.ROTATION_180);
+
+        assertEquals(Surface.ROTATION_0, mTarget.rotationForOrientation(
+                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90));
+    }
+
+    @Test
+    public void testReturnsSeascape_UserRotationLockedSeascape_AppRequestsSeascape()
+            throws Exception {
+        mBuilder.build();
+        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
+                false /* isTv */);
 
         freezeRotation(Surface.ROTATION_180);
 
         assertEquals(Surface.ROTATION_180, mTarget.rotationForOrientation(
-                ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, Surface.ROTATION_90));
+                ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, Surface.ROTATION_90));
+    }
+
+    @Test
+    public void testReturnsPortrait_UserRotationLockedPortrait_AppRequestsPortrait()
+            throws Exception {
+        mBuilder.build();
+        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
+                false /* isTv */);
+
+        freezeRotation(Surface.ROTATION_270);
+
+        assertEquals(Surface.ROTATION_270, mTarget.rotationForOrientation(
+                ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, Surface.ROTATION_0));
+    }
+
+    @Test
+    public void testReturnsUpsideDown_UserRotationLockedUpsideDown_AppRequestsUpsideDown()
+            throws Exception {
+        mBuilder.build();
+        configureDisplayRotation(SCREEN_ORIENTATION_LANDSCAPE, false /* isCar */,
+                false /* isTv */);
+
+        freezeRotation(Surface.ROTATION_90);
+
+        assertEquals(Surface.ROTATION_90, mTarget.rotationForOrientation(
+                ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, Surface.ROTATION_0));
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 0110e94..9d3c866 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -20,9 +20,10 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -49,6 +50,7 @@
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -57,10 +59,11 @@
  * Tests for the {@link DragDropController} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:DragDropControllerTests
+ *  atest WmTests:DragDropControllerTests
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class DragDropControllerTests extends WindowTestsBase {
     private static final int TIMEOUT_MS = 3000;
     private TestDragDropController mTarget;
@@ -121,29 +124,25 @@
     @Before
     public void setUp() throws Exception {
         mTarget = new TestDragDropController(mWm, mWm.mH.getLooper());
-        mDisplayContent = spy(mDisplayContent);
         mWindow = createDropTargetWindow("Drag test window", 0);
         doReturn(mWindow).when(mDisplayContent).getTouchableWinAtPointLocked(0, 0);
+        when(mWm.mInputManager.transferTouchFocus(any(), any())).thenReturn(true);
 
-        synchronized (mWm.mGlobalLock) {
-            mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
-        }
+        mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
     }
 
     @After
     public void tearDown() throws Exception {
         final CountDownLatch latch;
-        synchronized (mWm.mGlobalLock) {
-            if (!mTarget.dragDropActiveLocked()) {
-                return;
-            }
-            if (mToken != null) {
-                mTarget.cancelDragAndDrop(mToken, false);
-            }
-            latch = new CountDownLatch(1);
-            mTarget.setOnClosedCallbackLocked(latch::countDown);
+        if (!mTarget.dragDropActiveLocked()) {
+            return;
         }
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        if (mToken != null) {
+            mTarget.cancelDragAndDrop(mToken, false);
+        }
+        latch = new CountDownLatch(1);
+        mTarget.setOnClosedCallbackLocked(latch::countDown);
+        assertTrue(awaitInWmLock(() -> latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)));
     }
 
     @Test
@@ -177,6 +176,7 @@
                     .setFormat(PixelFormat.TRANSLUCENT)
                     .build();
 
+            assertTrue(mWm.mInputManager.transferTouchFocus(null, null));
             mToken = mTarget.performDrag(
                     new SurfaceSession(), 0, 0, mWindow.mClient, flag, surface, 0, 0, 0, 0, 0,
                     data);
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 94abd34..445a5cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -63,7 +63,6 @@
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
-import android.util.MutableLong;
 import android.util.SparseBooleanArray;
 
 import androidx.test.filters.MediumTest;
@@ -72,6 +71,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -86,6 +86,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class RecentTasksTest extends ActivityTestsBase {
     private static final int TEST_USER_0_ID = 0;
     private static final int TEST_USER_1_ID = 10;
@@ -95,10 +96,7 @@
     private static final int INVALID_STACK_ID = 999;
 
     private ActivityDisplay mDisplay;
-    private ActivityDisplay mOtherDisplay;
-    private ActivityDisplay mSingleTaskDisplay;
     private ActivityStack mStack;
-    private ActivityStack mHomeStack;
     private TestTaskPersister mTaskPersister;
     private TestRecentTasks mRecentTasks;
     private TestRunningTasks mRunningTasks;
@@ -111,15 +109,7 @@
     @Before
     public void setUp() throws Exception {
         mTaskPersister = new TestTaskPersister(mContext.getFilesDir());
-
-        // Set testing displays
         mDisplay = mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
-        mOtherDisplay = createNewActivityDisplay();
-        mSingleTaskDisplay = createNewActivityDisplay();
-        mSingleTaskDisplay.setDisplayToSingleTaskInstance();
-        mRootActivityContainer.addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP);
-        mRootActivityContainer.addChild(mDisplay, ActivityDisplay.POSITION_TOP);
-        mRootActivityContainer.addChild(mSingleTaskDisplay, ActivityDisplay.POSITION_TOP);
 
         // Set the recent tasks we should use for testing in this class.
         mRecentTasks = new TestRecentTasks(mService, mTaskPersister);
@@ -131,8 +121,6 @@
         mRunningTasks = new TestRunningTasks();
         mService.mStackSupervisor.setRunningTasks(mRunningTasks);
 
-        mHomeStack = mDisplay.getOrCreateStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
         mStack = mDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
         mCallbacksRecorder = new CallbacksRecorder();
@@ -269,7 +257,7 @@
         // other task
         TaskRecord task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
-                .setStack(mHomeStack).build();
+                .setStack(mDisplay.getHomeStack()).build();
         TaskRecord task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .setStack(mStack).build();
@@ -446,12 +434,12 @@
         mRecentTasks.add(task3);
         mRecentTasks.add(task4);
 
-        MutableLong prevLastActiveTime = new MutableLong(0);
+        long prevLastActiveTime = 0;
         final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
         for (int i = 0; i < tasks.size(); i++) {
             final TaskRecord task = tasks.get(i);
-            assertThat(prevLastActiveTime.value).isLessThan(task.lastActiveTime);
-            prevLastActiveTime.value = task.lastActiveTime;
+            assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime);
+            prevLastActiveTime = task.lastActiveTime;
         }
     }
 
@@ -618,7 +606,10 @@
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
 
-        ActivityStack singleTaskStack = mSingleTaskDisplay.createStack(
+        final ActivityDisplay singleTaskDisplay =
+                addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        singleTaskDisplay.setDisplayToSingleTaskInstance();
+        ActivityStack singleTaskStack = singleTaskDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
@@ -795,7 +786,8 @@
         mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
 
         final ActivityStack homeStack = mDisplay.getHomeStack();
-        final ActivityStack otherDisplayStack = mOtherDisplay.createStack(
+        final ActivityDisplay otherDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+        final ActivityStack otherDisplayStack = otherDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
         // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index f792b0d..5236b5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -66,15 +66,17 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 /**
  * Build/Install/Run:
- *  atest FrameworksServicesTests:RecentsAnimationControllerTest
+ *  atest WmTests:RecentsAnimationControllerTest
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class RecentsAnimationControllerTest extends WindowTestsBase {
 
     @Mock SurfaceControl mMockLeash;
@@ -88,12 +90,8 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        synchronized (mWm.mGlobalLock) {
-            // Hold the lock to protect the stubbing from being accessed by other threads.
-            spyOn(mWm.mRoot);
-            doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
-            doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
-        }
+        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+        doReturn(mDisplayContent).when(mWm.mRoot).getDisplayContent(anyInt());
         when(mMockRunner.asBinder()).thenReturn(new Binder());
         mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
                 DEFAULT_DISPLAY));
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index db105dd..afe18c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -31,6 +31,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for RootWindowContainer.
@@ -40,6 +41,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class RootWindowContainerTests extends WindowTestsBase {
 
     private static final int FAKE_CALLING_UID = 667;
@@ -91,18 +93,16 @@
 
     @Test
     public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
-        synchronized (mWm.mGlobalLock) {
-            assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
-                    mWm.getDefaultDisplayContentLocked().getWindowingMode());
+        assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+                mWm.getDefaultDisplayContentLocked().getWindowingMode());
 
-            mWm.mIsPc = true;
-            mWm.mAtmService.mSupportsFreeformWindowManagement = true;
+        mWm.mIsPc = true;
+        mWm.mAtmService.mSupportsFreeformWindowManagement = true;
 
-            mWm.mRoot.onSettingsRetrieved();
+        mWm.mRoot.onSettingsRetrieved();
 
-            assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
-                    mWm.getDefaultDisplayContentLocked().getWindowingMode());
-        }
+        assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+                mWm.getDefaultDisplayContentLocked().getWindowingMode());
     }
 }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 3e316f6..8326ad8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -35,6 +35,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 
@@ -44,6 +45,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class RunningTasksTest extends ActivityTestsBase {
 
     private static final ArraySet<Integer> PROFILE_IDS = new ArraySet<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
index 8d2a79b..2ad40f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -97,11 +97,6 @@
     }
 
     @Override
-    public SurfaceControl.Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
-        return this;
-    }
-
-    @Override
     public SurfaceControl.Transaction setGeometry(SurfaceControl sc, Rect sourceCrop,
             Rect destFrame, @Surface.Rotation int orientation) {
         return this;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
new file mode 100644
index 0000000..d1b6f6f
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java
@@ -0,0 +1,59 @@
+/*
+ * 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.wm;
+
+import android.os.Handler;
+import android.testing.DexmakerShareClassLoaderRule;
+
+import org.junit.Rule;
+
+import java.util.concurrent.Callable;
+
+/** The base class which provides the common rule for test classes under wm package. */
+class SystemServiceTestsBase {
+    @Rule
+    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
+            new DexmakerShareClassLoaderRule();
+    @Rule
+    public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
+
+    @WindowTestRunner.MethodWrapperRule
+    public final WindowManagerGlobalLockRule mLockRule =
+            new WindowManagerGlobalLockRule(mSystemServicesTestRule);
+
+    /** Waits until the main handler for WM has processed all messages. */
+    void waitUntilHandlersIdle() {
+        mLockRule.waitForLocked(mSystemServicesTestRule::waitUntilWindowManagerHandlersIdle);
+    }
+
+    boolean waitHandlerIdle(Handler handler) {
+        return waitHandlerIdle(handler, 0 /* timeout */);
+    }
+
+    boolean waitHandlerIdle(Handler handler, long timeout) {
+        return runWithScissors(handler, () -> { }, timeout);
+    }
+
+    boolean runWithScissors(Handler handler, Runnable r, long timeout) {
+        return mLockRule.runWithScissors(handler, r, timeout);
+    }
+
+    /** It is used when we want to wait for a result inside {@link WindowManagerGlobalLock}. */
+    <T> T awaitInWmLock(Callable<T> callable) {
+        return mLockRule.waitForLocked(callable);
+    }
+}
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 5a4d399..ef9821b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.os.Process.THREAD_PRIORITY_DEFAULT;
 import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
 import static android.view.Display.DEFAULT_DISPLAY;
 
@@ -36,7 +35,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
@@ -68,11 +66,12 @@
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
-import com.android.server.ServiceThread;
+import com.android.server.UiThread;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appop.AppOpsService;
 import com.android.server.display.color.ColorDisplayService;
+import com.android.server.firewall.IntentFirewall;
 import com.android.server.input.InputManagerService;
 import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PermissionPolicyInternal;
@@ -105,13 +104,13 @@
 
     private Context mContext;
     private StaticMockitoSession mMockitoSession;
-    ServiceThread mHandlerThread;
     private ActivityManagerService mAmService;
     private ActivityTaskManagerService mAtmService;
     private WindowManagerService mWmService;
     private TestWindowManagerPolicy mWMPolicy;
     private WindowState.PowerManagerWrapper mPowerManagerWrapper;
     private InputManagerService mImService;
+    private InputChannel mInputChannel;
     /**
      * Spied {@link SurfaceControl.Transaction} class than can be used to verify calls.
      */
@@ -147,10 +146,6 @@
     }
 
     private void setUpSystemCore() {
-        mHandlerThread = new ServiceThread(
-                "WmTestsThread", THREAD_PRIORITY_DEFAULT, true /* allowIo */);
-        mHandlerThread.start();
-
         doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
 
         mContext = getInstrumentation().getTargetContext();
@@ -181,6 +176,11 @@
         final AppOpsManager aom = mock(AppOpsManager.class);
         doReturn(aom).when(mContext).getSystemService(eq(Context.APP_OPS_SERVICE));
 
+        // Prevent "WakeLock finalized while still held: SCREEN_FROZEN".
+        final PowerManager pm = mock(PowerManager.class);
+        doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
+        doReturn(mock(PowerManager.WakeLock.class)).when(pm).newWakeLock(anyInt(), anyString());
+
         // DisplayManagerInternal
         final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
         doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class)));
@@ -214,11 +214,11 @@
 
         // InputManagerService
         mImService = mock(InputManagerService.class);
-        // InputChannel is final and can't be mocked.
-        final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
-        if (input != null && input.length > 1) {
-            doReturn(input[1]).when(mImService).monitorInput(anyString(), anyInt());
-        }
+        // InputChannel cannot be mocked because it may pass to InputEventReceiver.
+        final InputChannel[] inputChannels = InputChannel.openInputChannelPair(TAG);
+        inputChannels[0].dispose();
+        mInputChannel = inputChannels[1];
+        doReturn(mInputChannel).when(mImService).monitorInput(anyString(), anyInt());
 
         // StatusBarManagerInternal
         final StatusBarManagerInternal sbmi = mock(StatusBarManagerInternal.class);
@@ -227,8 +227,7 @@
 
     private void setUpActivityTaskManagerService() {
         // ActivityManagerService
-        mAmService = new ActivityManagerService(
-                new AMTestInjector(mContext, mHandlerThread), mHandlerThread);
+        mAmService = new ActivityManagerService(new AMTestInjector(mContext), null /* thread */);
         spyOn(mAmService);
         doReturn(mock(IPackageManager.class)).when(mAmService).getPackageManager();
         doNothing().when(mAmService).grantImplicitAccess(
@@ -246,6 +245,15 @@
         doNothing().when(amInternal).startProcess(
                 any(), any(), anyBoolean(), anyBoolean(), any(), any());
         doNothing().when(amInternal).updateOomLevelsForDisplay(anyInt());
+        doNothing().when(amInternal).broadcastGlobalConfigurationChanged(anyInt(), anyBoolean());
+        doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any());
+        doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
+        doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
+        doReturn(true).when(amInternal).isCurrentProfile(anyInt());
+        doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
+        doReturn(true).when(amInternal).hasStartedUserState(anyInt());
+        doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt());
+        doReturn(false).when(amInternal).isActivityStartsLoggingEnabled();
         LocalServices.addService(ActivityManagerInternal.class, amInternal);
 
         mAtmService = new TestActivityTaskManagerService(mContext, mAmService);
@@ -289,7 +297,6 @@
     }
 
     private void tearDown() {
-        waitUntilWindowManagerHandlersIdle();
         // Unregister display listener from root to avoid issues with subsequent tests.
         mContext.getSystemService(DisplayManager.class)
                 .unregisterDisplayListener(mAtmService.mRootActivityContainer);
@@ -297,37 +304,23 @@
         // a static object, so we need to clean it up in tearDown(), even though we didn't set up
         // in tests.
         DeviceConfig.removeOnPropertiesChangedListener(mWmService.mPropertiesChangedListener);
-        mWmService = null;
-        mWMPolicy = null;
-        mPowerManagerWrapper = null;
 
-        tearDownLocalServices();
-        tearDownSystemCore();
-
+        waitUntilWindowManagerHandlersIdle();
         // Needs to explicitly dispose current static threads because there could be messages
         // scheduled at a later time, and all mocks are invalid when it's executed.
         DisplayThread.dispose();
         AnimationThread.dispose();
+        UiThread.dispose();
+        mInputChannel.dispose();
+
+        tearDownLocalServices();
         // Reset priority booster because animation thread has been changed.
         WindowManagerService.sThreadPriorityBooster = new WindowManagerThreadPriorityBooster();
 
+        mMockitoSession.finishMocking();
         Mockito.framework().clearInlineMocks();
     }
 
-    private void tearDownSystemCore() {
-        if (mMockitoSession != null) {
-            mMockitoSession.finishMocking();
-            mMockitoSession = null;
-        }
-
-        if (mHandlerThread != null) {
-            // Make sure there are no running messages and then quit the thread so the next test
-            // won't be affected.
-            mHandlerThread.getThreadHandler().runWithScissors(mHandlerThread::quit,
-                    0 /* timeout */);
-        }
-    }
-
     private static void tearDownLocalServices() {
         LocalServices.removeServiceForTest(DisplayManagerInternal.class);
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
@@ -375,7 +368,6 @@
         waitHandlerIdle(wm.mH);
         waitHandlerIdle(wm.mAnimationHandler);
         waitHandlerIdle(SurfaceAnimationThread.getHandler());
-        waitHandlerIdle(mHandlerThread.getThreadHandler());
     }
 
     private void waitHandlerIdle(Handler handler) {
@@ -435,8 +427,12 @@
             ams.mActivityTaskManager = this;
             ams.mAtmInternal = mInternal;
             onActivityManagerInternalAdded();
-            initialize(
-                    ams.mIntentFirewall, ams.mPendingIntentController, mHandlerThread.getLooper());
+
+            final IntentFirewall intentFirewall = mock(IntentFirewall.class);
+            doReturn(true).when(intentFirewall).checkStartActivity(
+                    any(), anyInt(), anyInt(), nullable(String.class), any());
+            initialize(intentFirewall, null /* intentController */,
+                    DisplayThread.getHandler().getLooper());
             spyOn(getLifecycleManager());
             spyOn(getLockTaskController());
             spyOn(getTaskChangeNotificationController());
@@ -493,11 +489,9 @@
 
     // TODO: Can we just mock this?
     private static class AMTestInjector extends ActivityManagerService.Injector {
-        private ServiceThread mHandlerThread;
 
-        AMTestInjector(Context context, ServiceThread handlerThread) {
+        AMTestInjector(Context context) {
             super(context);
-            mHandlerThread = handlerThread;
         }
 
         @Override
@@ -512,7 +506,7 @@
 
         @Override
         public Handler getUiHandler(ActivityManagerService service) {
-            return mHandlerThread.getThreadHandler();
+            return UiThread.getHandler();
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index e6c9b9f..dd85f69 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -29,6 +29,8 @@
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
 
@@ -65,6 +67,10 @@
 @SmallTest
 @Presubmit
 public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
+    private static final Rect DISPLAY_BOUNDS = new Rect(/* left */ 0, /* top */ 0,
+            /* right */ 1920, /* bottom */ 1080);
+    private static final Rect DISPLAY_STABLE_BOUNDS = new Rect(/* left */ 100,
+            /* top */ 200, /* right */ 1620, /* bottom */ 680);
 
     private ActivityRecord mActivity;
 
@@ -614,7 +620,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(0, mResult.mBounds.left);
+        assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left);
     }
 
     @Test
@@ -630,7 +636,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(0, mResult.mBounds.top);
+        assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top);
     }
 
     @Test
@@ -646,8 +652,8 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(0, mResult.mBounds.left);
-        assertEquals(0, mResult.mBounds.top);
+        assertEquals(DISPLAY_STABLE_BOUNDS.left, mResult.mBounds.left);
+        assertEquals(DISPLAY_STABLE_BOUNDS.top, mResult.mBounds.top);
     }
 
     @Test
@@ -663,7 +669,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(1920, mResult.mBounds.right);
+        assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right);
     }
 
     @Test
@@ -679,7 +685,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(1080, mResult.mBounds.bottom);
+        assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom);
     }
 
     @Test
@@ -695,8 +701,8 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(1920, mResult.mBounds.right);
-        assertEquals(1080, mResult.mBounds.bottom);
+        assertEquals(DISPLAY_STABLE_BOUNDS.right, mResult.mBounds.right);
+        assertEquals(DISPLAY_STABLE_BOUNDS.bottom, mResult.mBounds.bottom);
     }
 
     @Test
@@ -712,7 +718,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+        assertEquals(new Rect(800, 400, 920, 480), mResult.mBounds);
     }
 
     @Test
@@ -728,7 +734,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds);
+        assertEquals(new Rect(100, 400, 220, 480), mResult.mBounds);
     }
 
     @Test
@@ -744,7 +750,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds);
+        assertEquals(new Rect(800, 200, 920, 280), mResult.mBounds);
     }
 
     @Test
@@ -760,7 +766,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds);
+        assertEquals(new Rect(100, 200, 220, 280), mResult.mBounds);
     }
 
     @Test
@@ -776,7 +782,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds);
+        assertEquals(new Rect(1500, 400, 1620, 480), mResult.mBounds);
     }
 
     @Test
@@ -792,7 +798,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds);
+        assertEquals(new Rect(800, 600, 920, 680), mResult.mBounds);
     }
 
     @Test
@@ -808,7 +814,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds);
+        assertEquals(new Rect(1500, 600, 1620, 680), mResult.mBounds);
     }
 
     @Test
@@ -819,12 +825,12 @@
         mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
 
         final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
-                .setWidthFraction(0.0625f).setHeightFraction(0.1f).build();
+                .setWidthFraction(0.125f).setHeightFraction(0.1f).build();
 
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
                 /* source */ null, /* options */ null, mCurrent, mResult));
 
-        assertEquals(new Rect(900, 486, 1020, 594), mResult.mBounds);
+        assertEquals(new Rect(765, 416, 955, 464), mResult.mBounds);
     }
 
     @Test
@@ -952,13 +958,12 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                 mActivity, /* source */ null, options, mCurrent, mResult));
 
-        final Rect displayBounds = freeformDisplay.getBounds();
         assertEquals("Distance to left and right should be equal.",
-                mResult.mBounds.left - displayBounds.left,
-                displayBounds.right - mResult.mBounds.right);
+                mResult.mBounds.left - DISPLAY_STABLE_BOUNDS.left,
+                DISPLAY_STABLE_BOUNDS.right - mResult.mBounds.right, /* delta */ 1);
         assertEquals("Distance to top and bottom should be equal.",
-                mResult.mBounds.top - displayBounds.top,
-                displayBounds.bottom - mResult.mBounds.bottom);
+                mResult.mBounds.top - DISPLAY_STABLE_BOUNDS.top,
+                DISPLAY_STABLE_BOUNDS.bottom - mResult.mBounds.bottom, /* delta */ 1);
     }
 
     @Test
@@ -1041,15 +1046,16 @@
         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
 
         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
-        mCurrent.mBounds.set(100, 200, 2120, 1380);
+        mCurrent.mBounds.set(100, 300, 1820, 1380);
 
         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
 
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                 mActivity, /* source */ null, options, mCurrent, mResult));
 
-        assertTrue("Result bounds should start from origin, but it's " + mResult.mBounds,
-                mResult.mBounds.left == 0 && mResult.mBounds.top == 0);
+        assertTrue("Result bounds should start from app bounds's origin, but it's "
+                        + mResult.mBounds,
+                mResult.mBounds.left == 100 && mResult.mBounds.top == 200);
     }
 
     @Test
@@ -1067,15 +1073,16 @@
         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
 
         mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
-        mCurrent.mBounds.set(100, 200, 2120, 1380);
+        mCurrent.mBounds.set(100, 300, 1820, 1380);
 
         mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
 
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                 mActivity, /* source */ null, options, mCurrent, mResult));
 
-        assertTrue("Result bounds should start from origin, but it's " + mResult.mBounds,
-                mResult.mBounds.left == -100 && mResult.mBounds.top == 0);
+        assertTrue("Result bounds should start from top-right corner of app bounds, but "
+                        + "it's " + mResult.mBounds,
+                mResult.mBounds.left == -100 && mResult.mBounds.top == 200);
     }
 
     @Test
@@ -1083,6 +1090,11 @@
         final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
                 WINDOWING_MODE_FREEFORM);
 
+        // This test case requires a relatively big app bounds to ensure the default size calculated
+        // by letterbox won't be too small to hold the minimum width/height.
+        freeformDisplay.mDisplayContent.mDisplayFrames.mStable.set(/* left */ 10, /* top */ 10,
+                /* right */ 1910, /* top */ 1070);
+
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchDisplayId(freeformDisplay.mDisplayId);
 
@@ -1245,7 +1257,7 @@
         assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
                 mActivity, /* source */ null, options, mCurrent, mResult));
 
-        assertEquals(new Rect(0, 0, 300, 300), mResult.mBounds);
+        assertEquals(new Rect(100, 200, 400, 500), mResult.mBounds);
     }
 
     @Test
@@ -1301,9 +1313,15 @@
     private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
         final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
         display.setWindowingMode(windowingMode);
-        display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080);
+        display.setBounds(DISPLAY_BOUNDS);
         display.getConfiguration().densityDpi = DENSITY_DEFAULT;
         display.getConfiguration().orientation = ORIENTATION_LANDSCAPE;
+        display.mDisplayContent.mDisplayFrames.mStable.set(DISPLAY_STABLE_BOUNDS);
+        spyOn(display.mDisplayContent.mDisplayFrames);
+
+        // We didn't set up the overall environment for this test, so we need to mute the side
+        // effect of layout passes that loosen the stable frame.
+        doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout();
         return display;
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 714d2f2..2ac5f7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -18,10 +18,10 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertFalse;
@@ -37,6 +37,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link TaskPositioningController} class.
@@ -46,6 +47,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskPositioningControllerTests extends WindowTestsBase {
     private static final int TIMEOUT_MS = 1000;
 
@@ -57,32 +59,29 @@
         assertNotNull(mWm.mTaskPositioningController);
         mTarget = mWm.mTaskPositioningController;
 
+        when(mWm.mInputManager.transferTouchFocus(
+                any(InputChannel.class),
+                any(InputChannel.class))).thenReturn(true);
+
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
         mWindow.mInputChannel = new InputChannel();
-        synchronized (mWm.mGlobalLock) {
-            mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
-            spyOn(mDisplayContent);
-            doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
-        }
+        mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
+        doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
     }
 
     @Test
     public void testStartAndFinishPositioning() {
-        synchronized (mWm.mGlobalLock) {
-            assertFalse(mTarget.isPositioningLocked());
-            assertNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
 
         assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
 
-        synchronized (mWm.mGlobalLock) {
-            assertTrue(mTarget.isPositioningLocked());
-            assertNotNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertTrue(mTarget.isPositioningLocked());
+        assertNotNull(mTarget.getDragWindowHandleLocked());
 
         mTarget.finishTaskPositioning();
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
+        assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
 
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
@@ -91,21 +90,17 @@
     @FlakyTest(bugId = 129507487)
     @Test
     public void testFinishPositioningWhenAppRequested() {
-        synchronized (mWm.mGlobalLock) {
-            assertFalse(mTarget.isPositioningLocked());
-            assertNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
 
         assertTrue(mTarget.startMovingTask(mWindow.mClient, 0, 0));
 
-        synchronized (mWm.mGlobalLock) {
-            assertTrue(mTarget.isPositioningLocked());
-            assertNotNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertTrue(mTarget.isPositioningLocked());
+        assertNotNull(mTarget.getDragWindowHandleLocked());
 
         mTarget.finishTaskPositioning(mWindow.mClient);
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
+        assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
 
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
@@ -113,10 +108,8 @@
 
     @Test
     public void testHandleTapOutsideTask() {
-        synchronized (mWm.mGlobalLock) {
-            assertFalse(mTarget.isPositioningLocked());
-            assertNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertFalse(mTarget.isPositioningLocked());
+        assertNull(mTarget.getDragWindowHandleLocked());
 
         final DisplayContent content = mock(DisplayContent.class);
         when(content.findTaskForResizePoint(anyInt(), anyInt())).thenReturn(mWindow.getTask());
@@ -124,16 +117,14 @@
 
         mTarget.handleTapOutsideTask(content, 0, 0);
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
+        assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
 
-        synchronized (mWm.mGlobalLock) {
-            assertTrue(mTarget.isPositioningLocked());
-            assertNotNull(mTarget.getDragWindowHandleLocked());
-        }
+        assertTrue(mTarget.isPositioningLocked());
+        assertNotNull(mTarget.getDragWindowHandleLocked());
 
         mTarget.finishTaskPositioning();
         // Wait until the looper processes finishTaskPositioning.
-        assertTrue(mWm.mH.runWithScissors(() -> { }, TIMEOUT_MS));
+        assertTrue(waitHandlerIdle(mWm.mH, TIMEOUT_MS));
 
         assertFalse(mTarget.isPositioningLocked());
         assertNull(mTarget.getDragWindowHandleLocked());
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 c83401b..d3588a2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -51,7 +51,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager;
@@ -78,6 +77,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -98,6 +98,7 @@
  */
 @MediumTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskRecordTests extends ActivityTestsBase {
 
     private static final String TASK_TAG = "task";
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index 74ccccc..5a0f7ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -32,15 +32,17 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:TaskStackContainersTests
+ *  atest WmTests:TaskStackContainersTests
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskStackContainersTests extends WindowTestsBase {
 
     private TaskStack mPinnedStack;
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 70ed62a..87713cb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -34,15 +34,17 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link TaskStack} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:TaskStackTests
+ *  atest WmTests:TaskStackTests
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskStackTests extends WindowTestsBase {
 
     @Test
@@ -149,7 +151,6 @@
         // After removing, the task will be isolated.
         assertNull(task.getParent());
         assertEquals(0, task.getChildCount());
-        assertNull(task.getController());
     }
 
     @Test
@@ -176,13 +177,8 @@
     public void testStackOutset() {
         final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
         final int stackOutset = 10;
-        // Clear the handler and hold the lock for mock, to prevent multi-thread issue.
-        waitUntilHandlersIdle();
-        synchronized (mWm.mGlobalLock) {
-            spyOn(stack);
-
-            doReturn(stackOutset).when(stack).getStackOutset();
-        }
+        spyOn(stack);
+        doReturn(stackOutset).when(stack).getStackOutset();
 
         final Rect stackBounds = new Rect(200, 200, 800, 1000);
         // Update surface position and size by the given bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 4184201..16fdf94 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -29,15 +29,17 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link Task}.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:TaskTests
+ *  atest WmTests:TaskTests
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class TaskTests extends WindowTestsBase {
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index a758681..09e5027 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -111,4 +111,8 @@
     @Override
     public void dispatchPointerCaptureChanged(boolean hasCapture) {
     }
+
+    @Override
+    public void showInsets(int types, boolean fromIme) throws RemoteException {
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index a91daf0..2e86178 100644
--- a/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -24,15 +24,17 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test class for {@link AppTransition}.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:UnknownAppVisibilityControllerTest
+ *  atest WmTests:UnknownAppVisibilityControllerTest
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class UnknownAppVisibilityControllerTest extends WindowTestsBase {
 
     @Before
@@ -48,7 +50,7 @@
         mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
 
         // Make sure our handler processed the message.
-        mWm.mH.runWithScissors(() -> { }, 0);
+        waitHandlerIdle(mWm.mH);
         assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
@@ -64,7 +66,7 @@
         mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
 
         // Make sure our handler processed the message.
-        mWm.mH.runWithScissors(() -> { }, 0);
+        waitHandlerIdle(mWm.mH);
         assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 6249bde..14d8a9d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -30,6 +30,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests for the {@link WallpaperController} class.
@@ -39,37 +40,36 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WallpaperControllerTests extends WindowTestsBase {
     @Test
     public void testWallpaperScreenshot() {
         WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class);
 
-        synchronized (mWm.mGlobalLock) {
-            // No wallpaper
-            final DisplayContent dc = createNewDisplay();
-            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
+        // No wallpaper
+        final DisplayContent dc = createNewDisplay();
+        assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
-            // No wallpaper WSA Surface
-            WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
-                    true, dc, true /* ownerCanManageAppTokens */);
-            WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
-                    wallpaperWindowToken, "wallpaperWindow");
-            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
+        // No wallpaper WSA Surface
+        WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
+                true, dc, true /* ownerCanManageAppTokens */);
+        WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
+                wallpaperWindowToken, "wallpaperWindow");
+        assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
-            // Wallpaper with not visible WSA surface.
-            wallpaperWindow.mWinAnimator.mSurfaceController = windowSurfaceController;
-            wallpaperWindow.mWinAnimator.mLastAlpha = 1;
-            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
+        // Wallpaper with not visible WSA surface.
+        wallpaperWindow.mWinAnimator.mSurfaceController = windowSurfaceController;
+        wallpaperWindow.mWinAnimator.mLastAlpha = 1;
+        assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
-            when(windowSurfaceController.getShown()).thenReturn(true);
+        when(windowSurfaceController.getShown()).thenReturn(true);
 
-            // Wallpaper with WSA alpha set to 0.
-            wallpaperWindow.mWinAnimator.mLastAlpha = 0;
-            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
+        // Wallpaper with WSA alpha set to 0.
+        wallpaperWindow.mWinAnimator.mLastAlpha = 0;
+        assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
-            // Wallpaper window with WSA Surface
-            wallpaperWindow.mWinAnimator.mLastAlpha = 1;
-            assertTrue(dc.mWallpaperController.canScreenshotWallpaper());
-        }
+        // Wallpaper window with WSA Surface
+        wallpaperWindow.mWinAnimator.mLastAlpha = 1;
+        assertTrue(dc.mWallpaperController.canScreenshotWallpaper());
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
deleted file mode 100644
index fc78635..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.content.res.Configuration.EMPTY;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.res.Configuration;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Test class for {@link WindowContainerController}.
- *
- * Build/Install/Run:
- *  atest WmTests:WindowContainerControllerTests
- */
-@SmallTest
-@Presubmit
-public class WindowContainerControllerTests extends WindowTestsBase {
-
-    @Test
-    public void testCreation() {
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-        final WindowContainer container = new WindowContainer(mWm);
-
-        container.setController(controller);
-        assertEquals(controller, container.getController());
-        assertEquals(controller.mContainer, container);
-    }
-
-    @Test
-    public void testSetContainer() {
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-        final WindowContainer container = new WindowContainer(mWm);
-
-        controller.setContainer(container);
-        assertEquals(controller.mContainer, container);
-
-        // Assert we can't change the container to another one once set
-        boolean gotException = false;
-        try {
-            controller.setContainer(new WindowContainer(mWm));
-        } catch (IllegalArgumentException e) {
-            gotException = true;
-        }
-        assertTrue(gotException);
-
-        // Assert that we can set the container to null.
-        controller.setContainer(null);
-        assertNull(controller.mContainer);
-    }
-
-    @Test
-    public void testRemoveContainer() {
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-        final WindowContainer container = new WindowContainer(mWm);
-
-        controller.setContainer(container);
-        assertEquals(controller.mContainer, container);
-
-        controller.removeContainer();
-        assertNull(controller.mContainer);
-    }
-
-    @Test
-    public void testOnOverrideConfigurationChanged() {
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-        final WindowContainer container = new WindowContainer(mWm);
-
-        controller.setContainer(container);
-        assertEquals(controller.mContainer, container);
-        assertEquals(EMPTY, container.getRequestedOverrideConfiguration());
-
-        final Configuration config = new Configuration();
-        config.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        config.windowConfiguration.setAppBounds(10, 10, 10, 10);
-
-        // Assert that the config change through the controller is propagated to the container.
-        controller.onRequestedOverrideConfigurationChanged(config);
-        assertEquals(config, container.getRequestedOverrideConfiguration());
-
-        // Assert the container configuration isn't changed after removal from the controller.
-        controller.removeContainer();
-        controller.onRequestedOverrideConfigurationChanged(EMPTY);
-        assertEquals(config, container.getRequestedOverrideConfiguration());
-    }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 921f105..8117ff6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -216,44 +216,6 @@
     }
 
     @Test
-    public void testRemoveImmediately_WithController() {
-        final WindowContainer container = new WindowContainer(mWm);
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-
-        container.setController(controller);
-        assertEquals(controller, container.getController());
-        assertEquals(container, controller.mContainer);
-
-        container.removeImmediately();
-        assertNull(container.getController());
-        assertNull(controller.mContainer);
-    }
-
-    @Test
-    public void testSetController() {
-        final WindowContainerController controller = new WindowContainerController<>(null, mWm);
-        final WindowContainer container = new WindowContainer(mWm);
-
-        container.setController(controller);
-        assertEquals(controller, container.getController());
-        assertEquals(container, controller.mContainer);
-
-        // Assert we can't change the controller to another one once set
-        boolean gotException = false;
-        try {
-            container.setController(new WindowContainerController<>(null, mWm));
-        } catch (IllegalArgumentException e) {
-            gotException = true;
-        }
-        assertTrue(gotException);
-
-        // Assert that we can set the controller to null.
-        container.setController(null);
-        assertNull(container.getController());
-        assertNull(controller.mContainer);
-    }
-
-    @Test
     public void testAddChildByIndex() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index 60cefe8..3563feb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -43,16 +43,18 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mockito;
 
 /**
  * Tests for the {@link WindowState#computeFrameLw} method and other window frame machinery.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:WindowFrameTests
+ *  atest WmTests:WindowFrameTests
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowFrameTests extends WindowTestsBase {
 
     private final IWindow mIWindow = new TestIWindow();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerGlobalLockRule.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerGlobalLockRule.java
index e0c314f..c5f13e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerGlobalLockRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerGlobalLockRule.java
@@ -27,6 +27,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -59,34 +62,41 @@
         return base;
     }
 
-    void waitUntilHandlersIdle() {
-        if (!mIsLocked) {
-            mSystemServicesTestRule.waitUntilWindowManagerHandlersIdle();
-            return;
-        }
-
-        waitForLocked(mSystemServicesTestRule::waitUntilWindowManagerHandlersIdle);
+    boolean runWithScissors(Handler handler, Runnable r, long timeout) {
+        return waitForLocked(() -> handler.runWithScissors(r, timeout));
     }
 
-    void runWithScissors(Handler handler, Runnable r, long timeout) {
-        if (!mIsLocked) {
-            handler.runWithScissors(r, timeout);
-            return;
-        }
-
-        waitForLocked(() -> handler.runWithScissors(r, timeout));
+    void waitForLocked(Runnable r) {
+        waitForLocked(() -> {
+            r.run();
+            return null;
+        });
     }
 
     /**
      * If the test holds the lock, we need to invoke {@link Object#wait} to release it so other
      * threads won't be blocked when we are waiting.
      */
-    private void waitForLocked(Runnable r) {
+    <T> T waitForLocked(Callable<T> callable) {
+        if (!mIsLocked) {
+            try {
+                return callable.call();
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
         final Object lock = mSystemServicesTestRule.getWindowManagerService().mGlobalLock;
         final AtomicBoolean done = new AtomicBoolean(false);
+        final List<T> result = Arrays.asList((T) null);
+        final Exception[] exception = { null };
 
         AsyncTask.SERIAL_EXECUTOR.execute(() -> {
-            r.run();
+            try {
+                result.set(0, callable.call());
+            } catch (Exception e) {
+                exception[0] = e;
+            }
             synchronized (lock) {
                 lock.notifyAll();
                 done.set(true);
@@ -101,6 +111,11 @@
                 }
             }
         }
+        if (exception[0] != null) {
+            throw new RuntimeException(exception[0]);
+        }
+
+        return result.get(0);
     }
 
     /** Wraps methods annotated with {@link org.junit.Test}. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 8c56ffa..cc90ca1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -26,13 +26,13 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
 
 import android.content.pm.ApplicationInfo;
 import android.platform.test.annotations.Presubmit;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
 
@@ -43,6 +43,7 @@
  *  atest WmTests:WindowProcessControllerTests
  */
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class WindowProcessControllerTests extends ActivityTestsBase {
 
     WindowProcessController mWpc;
@@ -97,7 +98,7 @@
     public void testSetRunningRecentsAnimation() {
         mWpc.setRunningRecentsAnimation(true);
         mWpc.setRunningRecentsAnimation(false);
-        mService.mH.runWithScissors(() -> {}, 0);
+        waitHandlerIdle(mService.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -108,7 +109,7 @@
     public void testSetRunningRemoteAnimation() {
         mWpc.setRunningRemoteAnimation(true);
         mWpc.setRunningRemoteAnimation(false);
-        mService.mH.runWithScissors(() -> {}, 0);
+        waitHandlerIdle(mService.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener).setRunningRemoteAnimation(eq(true));
@@ -122,7 +123,7 @@
 
         mWpc.setRunningRecentsAnimation(false);
         mWpc.setRunningRemoteAnimation(false);
-        mService.mH.runWithScissors(() -> {}, 0);
+        waitHandlerIdle(mService.mH);
 
         InOrder orderVerifier = Mockito.inOrder(mMockListener);
         orderVerifier.verify(mMockListener, times(3)).setRunningRemoteAnimation(eq(true));
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 f41f126..0503d74 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -57,6 +57,7 @@
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
 
 import android.graphics.Insets;
 import android.graphics.Matrix;
@@ -547,4 +548,29 @@
         assertEquals(OFFSET_SUM, values[Matrix.MTRANS_X], 0f);
         assertEquals(0f, values[Matrix.MTRANS_Y], 0f);
     }
+
+    @Test
+    public void testCantReceiveTouchDuringRecentsAnimation() {
+        final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
+
+        // Mock active recents animation
+        RecentsAnimationController recentsController = mock(RecentsAnimationController.class);
+        when(recentsController.isAnimatingTask(win0.mAppToken.getTask())).thenReturn(true);
+        mWm.setRecentsAnimationController(recentsController);
+        assertTrue(win0.cantReceiveTouchInput());
+    }
+
+    @Test
+    public void testCantReceiveTouchWhenAppTokenHiddenRequested() {
+        final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
+        win0.mAppToken.hiddenRequested = true;
+        assertTrue(win0.cantReceiveTouchInput());
+    }
+
+    @Test
+    public void testCantReceiveTouchWhenShouldIgnoreInput() {
+        final WindowState win0 = createWindow(null, TYPE_APPLICATION, "win0");
+        win0.mAppToken.getStack().setAdjustedForMinimizedDock(1 /* Any non 0 value works */);
+        assertTrue(win0.cantReceiveTouchInput());
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 8930e5a..c574b0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -42,7 +42,6 @@
 
 import android.content.Context;
 import android.content.res.Configuration;
-import android.testing.DexmakerShareClassLoaderRule;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -55,7 +54,6 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Rule;
 
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -65,7 +63,7 @@
  *
  * Make sure any requests to WM hold the WM lock if needed b/73966377
  */
-class WindowTestsBase {
+class WindowTestsBase extends SystemServiceTestsBase {
     private static final String TAG = WindowTestsBase.class.getSimpleName();
 
     WindowManagerService mWm;
@@ -92,16 +90,6 @@
      */
     Transaction mTransaction;
 
-    @Rule
-    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
-            new DexmakerShareClassLoaderRule();
-    @Rule
-    public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
-
-    @WindowTestRunner.MethodWrapperRule
-    public final WindowManagerGlobalLockRule mLockRule =
-            new WindowManagerGlobalLockRule(mSystemServicesTestRule);
-
     @BeforeClass
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
@@ -205,13 +193,6 @@
         }
     }
 
-    /**
-     * Waits until the main handler for WM has processed all messages.
-     */
-    void waitUntilHandlersIdle() {
-        mLockRule.waitUntilHandlersIdle();
-    }
-
     private WindowToken createWindowToken(
             DisplayContent dc, int windowingMode, int activityType, int type) {
         synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2105ab0..63b50b5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -47,6 +47,7 @@
 
 import org.junit.After;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -61,6 +62,7 @@
  */
 @SmallTest
 @Presubmit
+@RunWith(WindowTestRunner.class)
 public class ZOrderingTests extends WindowTestsBase {
 
     private static class LayerRecordingTransaction extends SurfaceControl.Transaction {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index e3183e3..59d0735 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -977,7 +977,9 @@
                 continue;
             }
             UserUsageStatsService service = mUserState.get(userId);
-            service.persistActiveStats();
+            if (service != null) {
+                service.persistActiveStats();
+            }
             mAppStandby.flushToDisk(userId);
         }
         mAppStandby.flushDurationsToDisk();
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
index 3c916a6..608fc2c 100644
--- a/services/wifi/Android.bp
+++ b/services/wifi/Android.bp
@@ -5,6 +5,9 @@
         "java/**/*.java",
         "java/**/*.aidl",
     ],
+    aidl: {
+        local_include_dirs: ["java"]
+    },
     libs: [
         "services.net",
     ],
diff --git a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
index eadc726..3af4666 100644
--- a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
+++ b/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
@@ -15,8 +15,9 @@
  */
 package android.net.wifi;
 
+import android.net.wifi.WifiApiServiceInfo;
+
 /** @hide */
 interface IWifiStackConnector {
-     IBinder retrieveApiServiceImpl(String serviceName);
-     boolean startApiService(String serviceName);
+     List<WifiApiServiceInfo> getWifiApiServiceInfos();
 }
diff --git a/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl b/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl
new file mode 100644
index 0000000..45e4c69
--- /dev/null
+++ b/services/wifi/java/android/net/wifi/WifiApiServiceInfo.aidl
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/** @hide */
+parcelable WifiApiServiceInfo {
+    String name;
+    IBinder binder;
+}
diff --git a/services/wifi/java/android/net/wifi/WifiStackClient.java b/services/wifi/java/android/net/wifi/WifiStackClient.java
index 64af7a8..dcdfbc5 100644
--- a/services/wifi/java/android/net/wifi/WifiStackClient.java
+++ b/services/wifi/java/android/net/wifi/WifiStackClient.java
@@ -21,12 +21,13 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.net.ConnectivityModuleConnector;
-import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
+import java.util.List;
+
 /**
  * Service used to communicate with the wifi stack, which could be running in a separate
  * module.
@@ -56,21 +57,23 @@
         @Override
         public void onModuleServiceConnected(IBinder service) {
             Log.i(TAG, "Wifi stack connected");
+            registerWifiStackService(service);
 
-            // spin up a new thread to not block system_server main thread
-            HandlerThread thread = new HandlerThread("InitWifiServicesThread");
-            thread.start();
-            thread.getThreadHandler().post(() -> {
-                registerWifiStackService(service);
-                IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service);
-                registerApiServiceAndStart(connector, Context.WIFI_SCANNING_SERVICE);
-                registerApiServiceAndStart(connector, Context.WIFI_SERVICE);
-                registerApiServiceAndStart(connector, Context.WIFI_P2P_SERVICE);
-                registerApiServiceAndStart(connector, Context.WIFI_AWARE_SERVICE);
-                registerApiServiceAndStart(connector, Context.WIFI_RTT_RANGING_SERVICE);
+            IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service);
 
-                thread.quitSafely();
-            });
+            List<WifiApiServiceInfo> wifiApiServiceInfos;
+            try {
+                wifiApiServiceInfos = connector.getWifiApiServiceInfos();
+            } catch (RemoteException e) {
+                throw new RuntimeException("Failed to getWifiApiServiceInfos()", e);
+            }
+
+            for (WifiApiServiceInfo wifiApiServiceInfo : wifiApiServiceInfos) {
+                String serviceName = wifiApiServiceInfo.name;
+                IBinder binder = wifiApiServiceInfo.binder;
+                Log.i(TAG, "Registering " + serviceName);
+                ServiceManager.addService(serviceName, binder);
+            }
         }
     }
 
@@ -81,32 +84,6 @@
         Log.i(TAG, "Wifi stack service registered");
     }
 
-    private void registerApiServiceAndStart(
-            IWifiStackConnector stackConnector, String serviceName) {
-        IBinder service = null;
-        try {
-            service = stackConnector.retrieveApiServiceImpl(serviceName);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Failed to retrieve service impl " + serviceName, e);
-        }
-        if (service == null) {
-            Log.i(TAG, "Service " + serviceName + " not available");
-            return;
-        }
-        Log.i(TAG, "Registering " + serviceName);
-        ServiceManager.addService(serviceName, service);
-
-        boolean success = false;
-        try {
-            success = stackConnector.startApiService(serviceName);
-        } catch (RemoteException e) {
-            throw new RuntimeException("Failed to start service " + serviceName, e);
-        }
-        if (!success) {
-            throw new RuntimeException("Service " + serviceName + " start failed");
-        }
-    }
-
     /**
      * Start the wifi stack. Should be called only once on device startup.
      *
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 1822cee..5e71416 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.net.Uri;
 import android.os.Build;
@@ -119,6 +120,20 @@
     public static final int STATE_PULLING_CALL = 11;
 
     /**
+     * The state of a call that is active with the network, but the audio from the call is
+     * being intercepted by an app on the local device. Telecom does not hold audio focus in this
+     * state, and the call will be invisible to the user except for a persistent notification.
+     */
+    public static final int STATE_AUDIO_PROCESSING = 12;
+
+    /**
+     * The state of a call that is being presented to the user after being in
+     * {@link #STATE_AUDIO_PROCESSING}. The call is still active with the network in this case, and
+     * Telecom will hold audio focus and play a ringtone if appropriate.
+     */
+    public static final int STATE_SIMULATED_RINGING = 13;
+
+    /**
      * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
      * extras. Used to pass the phone accounts to display on the front end to the user in order to
      * select phone accounts to (for example) place a call.
@@ -1479,6 +1494,49 @@
     }
 
     /**
+     * Instructs Telecom to put the call into the background audio processing state.
+     *
+     * This method can be called either when the call is in {@link #STATE_RINGING} or
+     * {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to
+     * {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in
+     * order to capture and play audio on the call stream.
+     *
+     * This method can only be called by the default dialer app.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO)
+    public void enterBackgroundAudioProcessing() {
+        if (mState != STATE_ACTIVE && mState != STATE_RINGING) {
+            throw new IllegalStateException("Call must be active or ringing");
+        }
+        mInCallAdapter.enterBackgroundAudioProcessing(mTelecomCallId);
+    }
+
+    /**
+     * Instructs Telecom to come out of the background audio processing state requested by
+     * {@link #enterBackgroundAudioProcessing()} or from the call screening service.
+     *
+     * This method can only be called when the call is in {@link #STATE_AUDIO_PROCESSING}.
+     *
+     * @param shouldRing If true, Telecom will put the call into the
+     *                   {@link #STATE_SIMULATED_RINGING} state and notify other apps that there is
+     *                   a ringing call. Otherwise, the call will go into {@link #STATE_ACTIVE}
+     *                   immediately.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    //@RequiresPermission(android.Manifest.permission.BACKGROUND_CALL_AUDIO)
+    public void exitBackgroundAudioProcessing(boolean shouldRing) {
+        if (mState != STATE_AUDIO_PROCESSING) {
+            throw new IllegalStateException("Call must in the audio processing state");
+        }
+        mInCallAdapter.exitBackgroundAudioProcessing(mTelecomCallId, shouldRing);
+    }
+
+    /**
      * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
      *
      * Any other currently playing DTMF tone in the specified call is immediately stopped.
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index e4f8d11..0d97567 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -136,23 +138,30 @@
         private final boolean mShouldSilenceCall;
         private final boolean mShouldSkipCallLog;
         private final boolean mShouldSkipNotification;
+        private final boolean mShouldScreenCallFurther;
 
         private CallResponse(
                 boolean shouldDisallowCall,
                 boolean shouldRejectCall,
                 boolean shouldSilenceCall,
                 boolean shouldSkipCallLog,
-                boolean shouldSkipNotification) {
+                boolean shouldSkipNotification,
+                boolean shouldScreenCallFurther) {
             if (!shouldDisallowCall
                     && (shouldRejectCall || shouldSkipCallLog || shouldSkipNotification)) {
                 throw new IllegalStateException("Invalid response state for allowed call.");
             }
 
+            if (shouldDisallowCall && shouldScreenCallFurther) {
+                throw new IllegalStateException("Invalid response state for allowed call.");
+            }
+
             mShouldDisallowCall = shouldDisallowCall;
             mShouldRejectCall = shouldRejectCall;
             mShouldSkipCallLog = shouldSkipCallLog;
             mShouldSkipNotification = shouldSkipNotification;
             mShouldSilenceCall = shouldSilenceCall;
+            mShouldScreenCallFurther = shouldScreenCallFurther;
         }
 
         /*
@@ -191,12 +200,22 @@
             return mShouldSkipNotification;
         }
 
+        /**
+         * @return Whether we should enter the {@link Call#STATE_AUDIO_PROCESSING} state to allow
+         * for further screening of the call.
+         * @hide
+         */
+        public boolean getShouldScreenCallFurther() {
+            return mShouldScreenCallFurther;
+        }
+
         public static class Builder {
             private boolean mShouldDisallowCall;
             private boolean mShouldRejectCall;
             private boolean mShouldSilenceCall;
             private boolean mShouldSkipCallLog;
             private boolean mShouldSkipNotification;
+            private boolean mShouldScreenCallFurther;
 
             /**
              * Sets whether the incoming call should be blocked.
@@ -252,13 +271,32 @@
                 return this;
             }
 
+            /**
+             * Sets whether to request background audio processing so that the in-call service can
+             * screen the call further. If set to {@code true}, {@link #setDisallowCall} should be
+             * called with {@code false}, and all other parameters in this builder will be ignored.
+             *
+             * This request will only be honored if the {@link CallScreeningService} shares the same
+             * uid as the default dialer app. Otherwise, the call will go through as usual.
+             *
+             * @param shouldScreenCallFurther Whether to request further call screening.
+             * @hide
+             */
+            @SystemApi
+            @TestApi
+            public Builder setShouldScreenCallFurther(boolean shouldScreenCallFurther) {
+                mShouldScreenCallFurther = shouldScreenCallFurther;
+                return this;
+            }
+
             public CallResponse build() {
                 return new CallResponse(
                         mShouldDisallowCall,
                         mShouldRejectCall,
                         mShouldSilenceCall,
                         mShouldSkipCallLog,
-                        mShouldSkipNotification);
+                        mShouldSkipNotification,
+                        mShouldScreenCallFurther);
             }
        }
     }
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index cd5fd97..d90f46d 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.telecom.Connection.VideoProvider;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
@@ -687,7 +688,7 @@
      *
      * @hide
      */
-    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+    public final void setCallRadioTech(@RilRadioTechnology int vrat) {
         putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
                 ServiceState.rilRadioTechnologyToNetworkType(vrat));
     }
@@ -700,7 +701,7 @@
      *
      * @hide
      */
-    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+    public final @RilRadioTechnology int getCallRadioTech() {
         int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         Bundle extras = getExtras();
         if (extras != null) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 0983eea..525b938 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -34,6 +34,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
 import android.util.ArraySet;
@@ -1958,7 +1959,7 @@
      *
      * @hide
      */
-    public final @ServiceState.RilRadioTechnology int getCallRadioTech() {
+    public final @RilRadioTechnology int getCallRadioTech() {
         int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
         Bundle extras = getExtras();
         if (extras != null) {
@@ -2409,7 +2410,7 @@
      *
      * @hide
      */
-    public final void setCallRadioTech(@ServiceState.RilRadioTechnology int vrat) {
+    public final void setCallRadioTech(@RilRadioTechnology int vrat) {
         putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
                 ServiceState.rilRadioTechnologyToNetworkType(vrat));
         // Propagates the call radio technology to its parent {@link android.telecom.Conference}
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 8678e33..2612468 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -16,8 +16,8 @@
 
 package android.telecom;
 
-import android.net.Uri;
 import android.bluetooth.BluetoothDevice;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
 
@@ -149,6 +149,26 @@
     }
 
     /**
+     * @see Call#enterBackgroundAudioProcessing()
+     */
+    public void enterBackgroundAudioProcessing(String callId) {
+        try {
+            mAdapter.enterBackgroundAudioProcessing(callId);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * @see Call#exitBackgroundAudioProcessing(boolean)
+     */
+    public void exitBackgroundAudioProcessing(String callId, boolean shouldRing) {
+        try {
+            mAdapter.exitBackgroundAudioProcessing(callId, shouldRing);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Request audio routing to a specific bluetooth device. Calling this method may result in
      * the device routing audio to a different bluetooth device than the one specified. A list of
      * available devices can be obtained via {@link CallAudioState#getSupportedBluetoothDevices()}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6409203..2bc20d5 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -33,6 +33,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.telephony.Annotation.CallState;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -1412,7 +1413,7 @@
      * @hide
      */
     @SystemApi
-    public @TelephonyManager.CallState int getCallState() {
+    public @CallState int getCallState() {
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getCallState();
@@ -2059,12 +2060,13 @@
     /**
      * Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
      * @param intent The {@link Intent#ACTION_CALL} intent to handle.
+     * @param callingPackageProxy The original package that called this before it was trampolined.
      * @hide
      */
-    public void handleCallIntent(Intent intent) {
+    public void handleCallIntent(Intent intent, String callingPackageProxy) {
         try {
             if (isServiceConnected()) {
-                getTelecomService().handleCallIntent(intent);
+                getTelecomService().handleCallIntent(intent, callingPackageProxy);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException handleCallIntent: " + e);
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index 3ee3285..83c8f62 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -30,6 +30,8 @@
 
     void silenceCall(String callId);
 
+    void screenCallFurther(String callId);
+
     void disallowCall(
             String callId,
             boolean shouldReject,
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 57df5c1..60745e4 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -44,6 +44,10 @@
 
     void setAudioRoute(int route, String bluetoothAddress);
 
+    void enterBackgroundAudioProcessing(String callId);
+
+    void exitBackgroundAudioProcessing(String callId, boolean shouldRing);
+
     void playDtmfTone(String callId, char digit);
 
     void stopDtmfTone(String callId);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 4fcda4d..6a1b78f 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -282,6 +282,11 @@
     void acceptHandover(in Uri srcAddr, int videoState, in PhoneAccountHandle destAcct);
 
     /**
+     * @see TelecomServiceImpl#setTestEmergencyPhoneAccountPackageNameFilter
+     */
+    void setTestEmergencyPhoneAccountPackageNameFilter(String packageName);
+
+    /**
      * @see TelecomServiceImpl#isInEmergencyCall
      */
     boolean isInEmergencyCall();
@@ -289,7 +294,7 @@
     /**
      * @see TelecomServiceImpl#handleCallIntent
      */
-    void handleCallIntent(in Intent intent);
+    void handleCallIntent(in Intent intent, in String callingPackageProxy);
 
     void setTestDefaultCallRedirectionApp(String packageName);
 
@@ -302,6 +307,11 @@
     void setTestAutoModeApp(String packageName);
 
     /**
+     * @see TelecomServiceImpl#setSystemDialer
+     */
+    void setSystemDialer(in ComponentName testComponentName);
+
+    /**
      * @see TelecomServiceImpl#setTestDefaultDialer
      */
     void setTestDefaultDialer(in String packageName);
diff --git a/telephony/java/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java
similarity index 100%
rename from telephony/java/com/google/android/mms/ContentType.java
rename to telephony/common/com/google/android/mms/ContentType.java
diff --git a/telephony/java/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java
similarity index 100%
rename from telephony/java/com/google/android/mms/InvalidHeaderValueException.java
rename to telephony/common/com/google/android/mms/InvalidHeaderValueException.java
diff --git a/telephony/java/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java
similarity index 100%
rename from telephony/java/com/google/android/mms/MmsException.java
rename to telephony/common/com/google/android/mms/MmsException.java
diff --git a/telephony/java/com/google/android/mms/package.html b/telephony/common/com/google/android/mms/package.html
similarity index 100%
rename from telephony/java/com/google/android/mms/package.html
rename to telephony/common/com/google/android/mms/package.html
diff --git a/telephony/java/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/AcknowledgeInd.java
rename to telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/Base64.java
rename to telephony/common/com/google/android/mms/pdu/Base64.java
diff --git a/telephony/java/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/CharacterSets.java
rename to telephony/common/com/google/android/mms/pdu/CharacterSets.java
diff --git a/telephony/java/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/DeliveryInd.java
rename to telephony/common/com/google/android/mms/pdu/DeliveryInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/EncodedStringValue.java
rename to telephony/common/com/google/android/mms/pdu/EncodedStringValue.java
diff --git a/telephony/java/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/GenericPdu.java
rename to telephony/common/com/google/android/mms/pdu/GenericPdu.java
diff --git a/telephony/java/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/MultimediaMessagePdu.java
rename to telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java
diff --git a/telephony/java/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/NotificationInd.java
rename to telephony/common/com/google/android/mms/pdu/NotificationInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/NotifyRespInd.java
rename to telephony/common/com/google/android/mms/pdu/NotifyRespInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduBody.java
rename to telephony/common/com/google/android/mms/pdu/PduBody.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduComposer.java
rename to telephony/common/com/google/android/mms/pdu/PduComposer.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduContentTypes.java
rename to telephony/common/com/google/android/mms/pdu/PduContentTypes.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduHeaders.java
rename to telephony/common/com/google/android/mms/pdu/PduHeaders.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduParser.java
rename to telephony/common/com/google/android/mms/pdu/PduParser.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduPart.java
rename to telephony/common/com/google/android/mms/pdu/PduPart.java
diff --git a/telephony/java/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/PduPersister.java
rename to telephony/common/com/google/android/mms/pdu/PduPersister.java
diff --git a/telephony/java/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/QuotedPrintable.java
rename to telephony/common/com/google/android/mms/pdu/QuotedPrintable.java
diff --git a/telephony/java/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/ReadOrigInd.java
rename to telephony/common/com/google/android/mms/pdu/ReadOrigInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/ReadRecInd.java
rename to telephony/common/com/google/android/mms/pdu/ReadRecInd.java
diff --git a/telephony/java/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/RetrieveConf.java
rename to telephony/common/com/google/android/mms/pdu/RetrieveConf.java
diff --git a/telephony/java/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/SendConf.java
rename to telephony/common/com/google/android/mms/pdu/SendConf.java
diff --git a/telephony/java/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/SendReq.java
rename to telephony/common/com/google/android/mms/pdu/SendReq.java
diff --git a/telephony/java/com/google/android/mms/pdu/package.html b/telephony/common/com/google/android/mms/pdu/package.html
similarity index 100%
rename from telephony/java/com/google/android/mms/pdu/package.html
rename to telephony/common/com/google/android/mms/pdu/package.html
diff --git a/telephony/java/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/AbstractCache.java
rename to telephony/common/com/google/android/mms/util/AbstractCache.java
diff --git a/telephony/java/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/DownloadDrmHelper.java
rename to telephony/common/com/google/android/mms/util/DownloadDrmHelper.java
diff --git a/telephony/java/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/DrmConvertSession.java
rename to telephony/common/com/google/android/mms/util/DrmConvertSession.java
diff --git a/telephony/java/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/PduCache.java
rename to telephony/common/com/google/android/mms/util/PduCache.java
diff --git a/telephony/java/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/PduCacheEntry.java
rename to telephony/common/com/google/android/mms/util/PduCacheEntry.java
diff --git a/telephony/java/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java
similarity index 100%
rename from telephony/java/com/google/android/mms/util/SqliteWrapper.java
rename to telephony/common/com/google/android/mms/util/SqliteWrapper.java
diff --git a/telephony/java/com/google/android/mms/util/package.html b/telephony/common/com/google/android/mms/util/package.html
similarity index 100%
rename from telephony/java/com/google/android/mms/util/package.html
rename to telephony/common/com/google/android/mms/util/package.html
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
new file mode 100644
index 0000000..72f758e
--- /dev/null
+++ b/telephony/java/android/telephony/Annotation.java
@@ -0,0 +1,512 @@
+package android.telephony;
+
+import android.annotation.IntDef;
+import android.telephony.data.ApnSetting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Telephony Annotations.
+ * Telephony sdk is a mainline module and others cannot reference hidden @IntDef. Moving some
+ * telephony annotations to a separate class to allow others statically link to it.
+ *
+ * @hide
+ */
+public class Annotation {
+    @IntDef(prefix = {"DATA_"}, value = {
+            TelephonyManager.DATA_ACTIVITY_NONE,
+            TelephonyManager.DATA_ACTIVITY_IN,
+            TelephonyManager.DATA_ACTIVITY_OUT,
+            TelephonyManager.DATA_ACTIVITY_INOUT,
+            TelephonyManager.DATA_ACTIVITY_DORMANT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataActivityType {
+    }
+
+    @IntDef(prefix = {"DATA_"}, value = {
+            TelephonyManager.DATA_UNKNOWN,
+            TelephonyManager.DATA_DISCONNECTED,
+            TelephonyManager.DATA_CONNECTING,
+            TelephonyManager.DATA_CONNECTED,
+            TelephonyManager.DATA_SUSPENDED,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataState {
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RADIO_POWER_"},
+            value = {
+                    TelephonyManager.RADIO_POWER_OFF,
+                    TelephonyManager.RADIO_POWER_ON,
+                    TelephonyManager.RADIO_POWER_UNAVAILABLE,
+            })
+    public @interface RadioPowerState {
+    }
+
+    @IntDef({
+            TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN,
+            TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING,
+            TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED,
+            TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED,
+            TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SimActivationState {
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"SRVCC_STATE_"},
+            value = {
+                    TelephonyManager.SRVCC_STATE_HANDOVER_NONE,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_STARTED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_COMPLETED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_FAILED,
+                    TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED})
+    public @interface SrvccState {
+    }
+
+    @IntDef(prefix = {"CALL_STATE_"}, value = {
+            TelephonyManager.CALL_STATE_IDLE,
+            TelephonyManager.CALL_STATE_RINGING,
+            TelephonyManager.CALL_STATE_OFFHOOK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CallState {
+    }
+
+    @IntDef({
+            TelephonyManager.NETWORK_TYPE_UNKNOWN,
+            TelephonyManager.NETWORK_TYPE_GPRS,
+            TelephonyManager.NETWORK_TYPE_EDGE,
+            TelephonyManager.NETWORK_TYPE_UMTS,
+            TelephonyManager.NETWORK_TYPE_CDMA,
+            TelephonyManager.NETWORK_TYPE_EVDO_0,
+            TelephonyManager.NETWORK_TYPE_EVDO_A,
+            TelephonyManager.NETWORK_TYPE_1xRTT,
+            TelephonyManager.NETWORK_TYPE_HSDPA,
+            TelephonyManager.NETWORK_TYPE_HSUPA,
+            TelephonyManager.NETWORK_TYPE_HSPA,
+            TelephonyManager.NETWORK_TYPE_IDEN,
+            TelephonyManager.NETWORK_TYPE_EVDO_B,
+            TelephonyManager.NETWORK_TYPE_LTE,
+            TelephonyManager.NETWORK_TYPE_EHRPD,
+            TelephonyManager.NETWORK_TYPE_HSPAP,
+            TelephonyManager.NETWORK_TYPE_GSM,
+            TelephonyManager.NETWORK_TYPE_TD_SCDMA,
+            TelephonyManager.NETWORK_TYPE_IWLAN,
+            TelephonyManager.NETWORK_TYPE_LTE_CA,
+            TelephonyManager.NETWORK_TYPE_NR,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface NetworkType {
+    }
+
+    @IntDef(flag = true, prefix = {"TYPE_"}, value = {
+            ApnSetting.TYPE_DEFAULT,
+            ApnSetting.TYPE_MMS,
+            ApnSetting.TYPE_SUPL,
+            ApnSetting.TYPE_DUN,
+            ApnSetting.TYPE_HIPRI,
+            ApnSetting.TYPE_FOTA,
+            ApnSetting.TYPE_IMS,
+            ApnSetting.TYPE_CBS,
+            ApnSetting.TYPE_IA,
+            ApnSetting.TYPE_EMERGENCY,
+            ApnSetting.TYPE_MCX
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApnType {
+    }
+
+    @IntDef(value = {
+            DataFailCause.NONE,
+            DataFailCause.OPERATOR_BARRED,
+            DataFailCause.NAS_SIGNALLING,
+            DataFailCause.LLC_SNDCP,
+            DataFailCause.INSUFFICIENT_RESOURCES,
+            DataFailCause.MISSING_UNKNOWN_APN,
+            DataFailCause.UNKNOWN_PDP_ADDRESS_TYPE,
+            DataFailCause.USER_AUTHENTICATION,
+            DataFailCause.ACTIVATION_REJECT_GGSN,
+            DataFailCause.ACTIVATION_REJECT_UNSPECIFIED,
+            DataFailCause.SERVICE_OPTION_NOT_SUPPORTED,
+            DataFailCause.SERVICE_OPTION_NOT_SUBSCRIBED,
+            DataFailCause.SERVICE_OPTION_OUT_OF_ORDER,
+            DataFailCause.NSAPI_IN_USE,
+            DataFailCause.REGULAR_DEACTIVATION,
+            DataFailCause.QOS_NOT_ACCEPTED,
+            DataFailCause.NETWORK_FAILURE,
+            DataFailCause.UMTS_REACTIVATION_REQ,
+            DataFailCause.FEATURE_NOT_SUPP,
+            DataFailCause.TFT_SEMANTIC_ERROR,
+            DataFailCause.TFT_SYTAX_ERROR,
+            DataFailCause.UNKNOWN_PDP_CONTEXT,
+            DataFailCause.FILTER_SEMANTIC_ERROR,
+            DataFailCause.FILTER_SYTAX_ERROR,
+            DataFailCause.PDP_WITHOUT_ACTIVE_TFT,
+            DataFailCause.ACTIVATION_REJECTED_BCM_VIOLATION,
+            DataFailCause.ONLY_IPV4_ALLOWED,
+            DataFailCause.ONLY_IPV6_ALLOWED,
+            DataFailCause.ONLY_SINGLE_BEARER_ALLOWED,
+            DataFailCause.ESM_INFO_NOT_RECEIVED,
+            DataFailCause.PDN_CONN_DOES_NOT_EXIST,
+            DataFailCause.MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
+            DataFailCause.COLLISION_WITH_NETWORK_INITIATED_REQUEST,
+            DataFailCause.ONLY_IPV4V6_ALLOWED,
+            DataFailCause.ONLY_NON_IP_ALLOWED,
+            DataFailCause.UNSUPPORTED_QCI_VALUE,
+            DataFailCause.BEARER_HANDLING_NOT_SUPPORTED,
+            DataFailCause.ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
+            DataFailCause.UNSUPPORTED_APN_IN_CURRENT_PLMN,
+            DataFailCause.INVALID_TRANSACTION_ID,
+            DataFailCause.MESSAGE_INCORRECT_SEMANTIC,
+            DataFailCause.INVALID_MANDATORY_INFO,
+            DataFailCause.MESSAGE_TYPE_UNSUPPORTED,
+            DataFailCause.MSG_TYPE_NONCOMPATIBLE_STATE,
+            DataFailCause.UNKNOWN_INFO_ELEMENT,
+            DataFailCause.CONDITIONAL_IE_ERROR,
+            DataFailCause.MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
+            DataFailCause.PROTOCOL_ERRORS,
+            DataFailCause.APN_TYPE_CONFLICT,
+            DataFailCause.INVALID_PCSCF_ADDR,
+            DataFailCause.INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
+            DataFailCause.EMM_ACCESS_BARRED,
+            DataFailCause.EMERGENCY_IFACE_ONLY,
+            DataFailCause.IFACE_MISMATCH,
+            DataFailCause.COMPANION_IFACE_IN_USE,
+            DataFailCause.IP_ADDRESS_MISMATCH,
+            DataFailCause.IFACE_AND_POL_FAMILY_MISMATCH,
+            DataFailCause.EMM_ACCESS_BARRED_INFINITE_RETRY,
+            DataFailCause.AUTH_FAILURE_ON_EMERGENCY_CALL,
+            DataFailCause.INVALID_DNS_ADDR,
+            DataFailCause.INVALID_PCSCF_OR_DNS_ADDRESS,
+            DataFailCause.CALL_PREEMPT_BY_EMERGENCY_APN,
+            DataFailCause.UE_INITIATED_DETACH_OR_DISCONNECT,
+            DataFailCause.MIP_FA_REASON_UNSPECIFIED,
+            DataFailCause.MIP_FA_ADMIN_PROHIBITED,
+            DataFailCause.MIP_FA_INSUFFICIENT_RESOURCES,
+            DataFailCause.MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_FA_REQUESTED_LIFETIME_TOO_LONG,
+            DataFailCause.MIP_FA_MALFORMED_REQUEST,
+            DataFailCause.MIP_FA_MALFORMED_REPLY,
+            DataFailCause.MIP_FA_ENCAPSULATION_UNAVAILABLE,
+            DataFailCause.MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
+            DataFailCause.MIP_FA_REVERSE_TUNNEL_UNAVAILABLE,
+            DataFailCause.MIP_FA_REVERSE_TUNNEL_IS_MANDATORY,
+            DataFailCause.MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
+            DataFailCause.MIP_FA_MISSING_NAI,
+            DataFailCause.MIP_FA_MISSING_HOME_AGENT,
+            DataFailCause.MIP_FA_MISSING_HOME_ADDRESS,
+            DataFailCause.MIP_FA_UNKNOWN_CHALLENGE,
+            DataFailCause.MIP_FA_MISSING_CHALLENGE,
+            DataFailCause.MIP_FA_STALE_CHALLENGE,
+            DataFailCause.MIP_HA_REASON_UNSPECIFIED,
+            DataFailCause.MIP_HA_ADMIN_PROHIBITED,
+            DataFailCause.MIP_HA_INSUFFICIENT_RESOURCES,
+            DataFailCause.MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
+            DataFailCause.MIP_HA_REGISTRATION_ID_MISMATCH,
+            DataFailCause.MIP_HA_MALFORMED_REQUEST,
+            DataFailCause.MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS,
+            DataFailCause.MIP_HA_REVERSE_TUNNEL_UNAVAILABLE,
+            DataFailCause.MIP_HA_REVERSE_TUNNEL_IS_MANDATORY,
+            DataFailCause.MIP_HA_ENCAPSULATION_UNAVAILABLE,
+            DataFailCause.CLOSE_IN_PROGRESS,
+            DataFailCause.NETWORK_INITIATED_TERMINATION,
+            DataFailCause.MODEM_APP_PREEMPTED,
+            DataFailCause.PDN_IPV4_CALL_DISALLOWED,
+            DataFailCause.PDN_IPV4_CALL_THROTTLED,
+            DataFailCause.PDN_IPV6_CALL_DISALLOWED,
+            DataFailCause.PDN_IPV6_CALL_THROTTLED,
+            DataFailCause.MODEM_RESTART,
+            DataFailCause.PDP_PPP_NOT_SUPPORTED,
+            DataFailCause.UNPREFERRED_RAT,
+            DataFailCause.PHYSICAL_LINK_CLOSE_IN_PROGRESS,
+            DataFailCause.APN_PENDING_HANDOVER,
+            DataFailCause.PROFILE_BEARER_INCOMPATIBLE,
+            DataFailCause.SIM_CARD_CHANGED,
+            DataFailCause.LOW_POWER_MODE_OR_POWERING_DOWN,
+            DataFailCause.APN_DISABLED,
+            DataFailCause.MAX_PPP_INACTIVITY_TIMER_EXPIRED,
+            DataFailCause.IPV6_ADDRESS_TRANSFER_FAILED,
+            DataFailCause.TRAT_SWAP_FAILED,
+            DataFailCause.EHRPD_TO_HRPD_FALLBACK,
+            DataFailCause.MIP_CONFIG_FAILURE,
+            DataFailCause.PDN_INACTIVITY_TIMER_EXPIRED,
+            DataFailCause.MAX_IPV4_CONNECTIONS,
+            DataFailCause.MAX_IPV6_CONNECTIONS,
+            DataFailCause.APN_MISMATCH,
+            DataFailCause.IP_VERSION_MISMATCH,
+            DataFailCause.DUN_CALL_DISALLOWED,
+            DataFailCause.INTERNAL_EPC_NONEPC_TRANSITION,
+            DataFailCause.INTERFACE_IN_USE,
+            DataFailCause.APN_DISALLOWED_ON_ROAMING,
+            DataFailCause.APN_PARAMETERS_CHANGED,
+            DataFailCause.NULL_APN_DISALLOWED,
+            DataFailCause.THERMAL_MITIGATION,
+            DataFailCause.DATA_SETTINGS_DISABLED,
+            DataFailCause.DATA_ROAMING_SETTINGS_DISABLED,
+            DataFailCause.DDS_SWITCHED,
+            DataFailCause.FORBIDDEN_APN_NAME,
+            DataFailCause.DDS_SWITCH_IN_PROGRESS,
+            DataFailCause.CALL_DISALLOWED_IN_ROAMING,
+            DataFailCause.NON_IP_NOT_SUPPORTED,
+            DataFailCause.PDN_NON_IP_CALL_THROTTLED,
+            DataFailCause.PDN_NON_IP_CALL_DISALLOWED,
+            DataFailCause.CDMA_LOCK,
+            DataFailCause.CDMA_INTERCEPT,
+            DataFailCause.CDMA_REORDER,
+            DataFailCause.CDMA_RELEASE_DUE_TO_SO_REJECTION,
+            DataFailCause.CDMA_INCOMING_CALL,
+            DataFailCause.CDMA_ALERT_STOP,
+            DataFailCause.CHANNEL_ACQUISITION_FAILURE,
+            DataFailCause.MAX_ACCESS_PROBE,
+            DataFailCause.CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
+            DataFailCause.NO_RESPONSE_FROM_BASE_STATION,
+            DataFailCause.REJECTED_BY_BASE_STATION,
+            DataFailCause.CONCURRENT_SERVICES_INCOMPATIBLE,
+            DataFailCause.NO_CDMA_SERVICE,
+            DataFailCause.RUIM_NOT_PRESENT,
+            DataFailCause.CDMA_RETRY_ORDER,
+            DataFailCause.ACCESS_BLOCK,
+            DataFailCause.ACCESS_BLOCK_ALL,
+            DataFailCause.IS707B_MAX_ACCESS_PROBES,
+            DataFailCause.THERMAL_EMERGENCY,
+            DataFailCause.CONCURRENT_SERVICES_NOT_ALLOWED,
+            DataFailCause.INCOMING_CALL_REJECTED,
+            DataFailCause.NO_SERVICE_ON_GATEWAY,
+            DataFailCause.NO_GPRS_CONTEXT,
+            DataFailCause.ILLEGAL_MS,
+            DataFailCause.ILLEGAL_ME,
+            DataFailCause.GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
+            DataFailCause.GPRS_SERVICES_NOT_ALLOWED,
+            DataFailCause.MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
+            DataFailCause.IMPLICITLY_DETACHED,
+            DataFailCause.PLMN_NOT_ALLOWED,
+            DataFailCause.LOCATION_AREA_NOT_ALLOWED,
+            DataFailCause.GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
+            DataFailCause.PDP_DUPLICATE,
+            DataFailCause.UE_RAT_CHANGE,
+            DataFailCause.CONGESTION,
+            DataFailCause.NO_PDP_CONTEXT_ACTIVATED,
+            DataFailCause.ACCESS_CLASS_DSAC_REJECTION,
+            DataFailCause.PDP_ACTIVATE_MAX_RETRY_FAILED,
+            DataFailCause.RADIO_ACCESS_BEARER_FAILURE,
+            DataFailCause.ESM_UNKNOWN_EPS_BEARER_CONTEXT,
+            DataFailCause.DRB_RELEASED_BY_RRC,
+            DataFailCause.CONNECTION_RELEASED,
+            DataFailCause.EMM_DETACHED,
+            DataFailCause.EMM_ATTACH_FAILED,
+            DataFailCause.EMM_ATTACH_STARTED,
+            DataFailCause.LTE_NAS_SERVICE_REQUEST_FAILED,
+            DataFailCause.DUPLICATE_BEARER_ID,
+            DataFailCause.ESM_COLLISION_SCENARIOS,
+            DataFailCause.ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
+            DataFailCause.ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
+            DataFailCause.ESM_BAD_OTA_MESSAGE,
+            DataFailCause.ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
+            DataFailCause.ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
+            DataFailCause.DS_EXPLICIT_DEACTIVATION,
+            DataFailCause.ESM_LOCAL_CAUSE_NONE,
+            DataFailCause.LTE_THROTTLING_NOT_REQUIRED,
+            DataFailCause.ACCESS_CONTROL_LIST_CHECK_FAILURE,
+            DataFailCause.SERVICE_NOT_ALLOWED_ON_PLMN,
+            DataFailCause.EMM_T3417_EXPIRED,
+            DataFailCause.EMM_T3417_EXT_EXPIRED,
+            DataFailCause.RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
+            DataFailCause.RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
+            DataFailCause.RRC_UPLINK_CONNECTION_RELEASE,
+            DataFailCause.RRC_UPLINK_RADIO_LINK_FAILURE,
+            DataFailCause.RRC_UPLINK_ERROR_REQUEST_FROM_NAS,
+            DataFailCause.RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
+            DataFailCause.RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
+            DataFailCause.RRC_CONNECTION_ACCESS_BARRED,
+            DataFailCause.RRC_CONNECTION_CELL_RESELECTION,
+            DataFailCause.RRC_CONNECTION_CONFIG_FAILURE,
+            DataFailCause.RRC_CONNECTION_TIMER_EXPIRED,
+            DataFailCause.RRC_CONNECTION_LINK_FAILURE,
+            DataFailCause.RRC_CONNECTION_CELL_NOT_CAMPED,
+            DataFailCause.RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
+            DataFailCause.RRC_CONNECTION_REJECT_BY_NETWORK,
+            DataFailCause.RRC_CONNECTION_NORMAL_RELEASE,
+            DataFailCause.RRC_CONNECTION_RADIO_LINK_FAILURE,
+            DataFailCause.RRC_CONNECTION_REESTABLISHMENT_FAILURE,
+            DataFailCause.RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
+            DataFailCause.RRC_CONNECTION_ABORT_REQUEST,
+            DataFailCause.RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
+            DataFailCause.NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
+            DataFailCause.NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
+            DataFailCause.ESM_PROCEDURE_TIME_OUT,
+            DataFailCause.INVALID_CONNECTION_ID,
+            DataFailCause.MAXIMIUM_NSAPIS_EXCEEDED,
+            DataFailCause.INVALID_PRIMARY_NSAPI,
+            DataFailCause.CANNOT_ENCODE_OTA_MESSAGE,
+            DataFailCause.RADIO_ACCESS_BEARER_SETUP_FAILURE,
+            DataFailCause.PDP_ESTABLISH_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_MODIFY_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_INACTIVE_TIMEOUT_EXPIRED,
+            DataFailCause.PDP_LOWERLAYER_ERROR,
+            DataFailCause.PDP_MODIFY_COLLISION,
+            DataFailCause.MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
+            DataFailCause.NAS_REQUEST_REJECTED_BY_NETWORK,
+            DataFailCause.RRC_CONNECTION_INVALID_REQUEST,
+            DataFailCause.RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
+            DataFailCause.RRC_CONNECTION_RF_UNAVAILABLE,
+            DataFailCause.RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
+            DataFailCause.RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
+            DataFailCause.RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
+            DataFailCause.RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
+            DataFailCause.RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
+            DataFailCause.IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
+            DataFailCause.IMEI_NOT_ACCEPTED,
+            DataFailCause.EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
+            DataFailCause.EPS_SERVICES_NOT_ALLOWED_IN_PLMN,
+            DataFailCause.MSC_TEMPORARILY_NOT_REACHABLE,
+            DataFailCause.CS_DOMAIN_NOT_AVAILABLE,
+            DataFailCause.ESM_FAILURE,
+            DataFailCause.MAC_FAILURE,
+            DataFailCause.SYNCHRONIZATION_FAILURE,
+            DataFailCause.UE_SECURITY_CAPABILITIES_MISMATCH,
+            DataFailCause.SECURITY_MODE_REJECTED,
+            DataFailCause.UNACCEPTABLE_NON_EPS_AUTHENTICATION,
+            DataFailCause.CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
+            DataFailCause.NO_EPS_BEARER_CONTEXT_ACTIVATED,
+            DataFailCause.INVALID_EMM_STATE,
+            DataFailCause.NAS_LAYER_FAILURE,
+            DataFailCause.MULTIPLE_PDP_CALL_NOT_ALLOWED,
+            DataFailCause.EMBMS_NOT_ENABLED,
+            DataFailCause.IRAT_HANDOVER_FAILED,
+            DataFailCause.EMBMS_REGULAR_DEACTIVATION,
+            DataFailCause.TEST_LOOPBACK_REGULAR_DEACTIVATION,
+            DataFailCause.LOWER_LAYER_REGISTRATION_FAILURE,
+            DataFailCause.DATA_PLAN_EXPIRED,
+            DataFailCause.UMTS_HANDOVER_TO_IWLAN,
+            DataFailCause.EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
+            DataFailCause.EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
+            DataFailCause.EVDO_HDR_CHANGED,
+            DataFailCause.EVDO_HDR_EXITED,
+            DataFailCause.EVDO_HDR_NO_SESSION,
+            DataFailCause.EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
+            DataFailCause.EVDO_HDR_CONNECTION_SETUP_TIMEOUT,
+            DataFailCause.FAILED_TO_ACQUIRE_COLOCATED_HDR,
+            DataFailCause.OTASP_COMMIT_IN_PROGRESS,
+            DataFailCause.NO_HYBRID_HDR_SERVICE,
+            DataFailCause.HDR_NO_LOCK_GRANTED,
+            DataFailCause.DBM_OR_SMS_IN_PROGRESS,
+            DataFailCause.HDR_FADE,
+            DataFailCause.HDR_ACCESS_FAILURE,
+            DataFailCause.UNSUPPORTED_1X_PREV,
+            DataFailCause.LOCAL_END,
+            DataFailCause.NO_SERVICE,
+            DataFailCause.FADE,
+            DataFailCause.NORMAL_RELEASE,
+            DataFailCause.ACCESS_ATTEMPT_ALREADY_IN_PROGRESS,
+            DataFailCause.REDIRECTION_OR_HANDOFF_IN_PROGRESS,
+            DataFailCause.EMERGENCY_MODE,
+            DataFailCause.PHONE_IN_USE,
+            DataFailCause.INVALID_MODE,
+            DataFailCause.INVALID_SIM_STATE,
+            DataFailCause.NO_COLLOCATED_HDR,
+            DataFailCause.UE_IS_ENTERING_POWERSAVE_MODE,
+            DataFailCause.DUAL_SWITCH,
+            DataFailCause.PPP_TIMEOUT,
+            DataFailCause.PPP_AUTH_FAILURE,
+            DataFailCause.PPP_OPTION_MISMATCH,
+            DataFailCause.PPP_PAP_FAILURE,
+            DataFailCause.PPP_CHAP_FAILURE,
+            DataFailCause.PPP_CLOSE_IN_PROGRESS,
+            DataFailCause.LIMITED_TO_IPV4,
+            DataFailCause.LIMITED_TO_IPV6,
+            DataFailCause.VSNCP_TIMEOUT,
+            DataFailCause.VSNCP_GEN_ERROR,
+            DataFailCause.VSNCP_APN_UNATHORIZED,
+            DataFailCause.VSNCP_PDN_LIMIT_EXCEEDED,
+            DataFailCause.VSNCP_NO_PDN_GATEWAY_ADDRESS,
+            DataFailCause.VSNCP_PDN_GATEWAY_UNREACHABLE,
+            DataFailCause.VSNCP_PDN_GATEWAY_REJECT,
+            DataFailCause.VSNCP_INSUFFICIENT_PARAMETERS,
+            DataFailCause.VSNCP_RESOURCE_UNAVAILABLE,
+            DataFailCause.VSNCP_ADMINISTRATIVELY_PROHIBITED,
+            DataFailCause.VSNCP_PDN_ID_IN_USE,
+            DataFailCause.VSNCP_SUBSCRIBER_LIMITATION,
+            DataFailCause.VSNCP_PDN_EXISTS_FOR_THIS_APN,
+            DataFailCause.VSNCP_RECONNECT_NOT_ALLOWED,
+            DataFailCause.IPV6_PREFIX_UNAVAILABLE,
+            DataFailCause.HANDOFF_PREFERENCE_CHANGED,
+            DataFailCause.OEM_DCFAILCAUSE_1,
+            DataFailCause.OEM_DCFAILCAUSE_2,
+            DataFailCause.OEM_DCFAILCAUSE_3,
+            DataFailCause.OEM_DCFAILCAUSE_4,
+            DataFailCause.OEM_DCFAILCAUSE_5,
+            DataFailCause.OEM_DCFAILCAUSE_6,
+            DataFailCause.OEM_DCFAILCAUSE_7,
+            DataFailCause.OEM_DCFAILCAUSE_8,
+            DataFailCause.OEM_DCFAILCAUSE_9,
+            DataFailCause.OEM_DCFAILCAUSE_10,
+            DataFailCause.OEM_DCFAILCAUSE_11,
+            DataFailCause.OEM_DCFAILCAUSE_12,
+            DataFailCause.OEM_DCFAILCAUSE_13,
+            DataFailCause.OEM_DCFAILCAUSE_14,
+            DataFailCause.OEM_DCFAILCAUSE_15,
+            DataFailCause.REGISTRATION_FAIL,
+            DataFailCause.GPRS_REGISTRATION_FAIL,
+            DataFailCause.SIGNAL_LOST,
+            DataFailCause.PREF_RADIO_TECH_CHANGED,
+            DataFailCause.RADIO_POWER_OFF,
+            DataFailCause.TETHERED_CALL_ACTIVE,
+            DataFailCause.ERROR_UNSPECIFIED,
+            DataFailCause.UNKNOWN,
+            DataFailCause.RADIO_NOT_AVAILABLE,
+            DataFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
+            DataFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN,
+            DataFailCause.LOST_CONNECTION,
+            DataFailCause.RESET_BY_FRAMEWORK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataFailureCause {
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"PRECISE_CALL_STATE_"},
+            value = {
+            PreciseCallState.PRECISE_CALL_STATE_NOT_VALID,
+            PreciseCallState.PRECISE_CALL_STATE_IDLE,
+            PreciseCallState.PRECISE_CALL_STATE_ACTIVE,
+            PreciseCallState.PRECISE_CALL_STATE_HOLDING,
+            PreciseCallState.PRECISE_CALL_STATE_DIALING,
+            PreciseCallState.PRECISE_CALL_STATE_ALERTING,
+            PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+            PreciseCallState.PRECISE_CALL_STATE_WAITING,
+            PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
+            PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
+    public @interface PreciseCallStates {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"RIL_RADIO_TECHNOLOGY_" }, value = {
+            ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN,
+            ServiceState.RIL_RADIO_TECHNOLOGY_GPRS,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EDGE,
+            ServiceState.RIL_RADIO_TECHNOLOGY_UMTS,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IS95A,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IS95B,
+            ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSPA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B,
+            ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD,
+            ServiceState.RIL_RADIO_TECHNOLOGY_LTE,
+            ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP,
+            ServiceState.RIL_RADIO_TECHNOLOGY_GSM,
+            ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN,
+            ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA,
+            ServiceState.RIL_RADIO_TECHNOLOGY_NR})
+    public @interface RilRadioTechnology {}
+}
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 1c03d80..cd830ad 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -21,8 +21,8 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.util.Objects;
 
 /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b449578..1d5c18d 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1739,9 +1739,8 @@
             "allow_emergency_video_calls_bool";
 
     /**
-     * Flag indicating whether the carrier supports RCS presence indication for video calls.  When
-     * {@code true}, the carrier supports RCS presence indication for video calls.  When presence
-     * is supported, the device should use the
+     * Flag indicating whether the carrier supports RCS presence indication for
+     * User Capability Exchange (UCE).  When presence is supported, the device should use the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} bit mask and set the
      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit to indicate
      * whether each contact supports video calling.  The UI is made aware that presence is enabled
@@ -1752,6 +1751,12 @@
     public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool";
 
     /**
+     * Flag indicating whether the carrier supports RCS SIP OPTIONS indication for
+     * User Capability Exchange (UCE).
+     */
+    public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool";
+
+    /**
      * The duration in seconds that platform call and message blocking is disabled after the user
      * contacts emergency services. Platform considers values for below cases:
      *  1) 0 <= VALUE <= 604800(one week): the value will be used as the duration directly.
@@ -3435,6 +3440,7 @@
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
         sDefaults.putInt(KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT, 0);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
+        sDefaults.putBoolean(KEY_USE_RCS_SIP_OPTIONS_BOOL, false);
         sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
         sDefaults.putInt(
                 KEY_CDMA_ROAMING_MODE_INT, TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index ca264f7..246bec7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.os.PersistableBundle;
 
+import android.telephony.Annotation.DataFailureCause;
 import com.android.internal.util.ArrayUtils;
 
 import java.lang.annotation.Retention;
@@ -968,355 +969,6 @@
      */
     public static final int HANDOVER_FAILED = 0x10006;
 
-    /** @hide */
-    @IntDef(value = {
-            NONE,
-            OPERATOR_BARRED,
-            NAS_SIGNALLING,
-            LLC_SNDCP,
-            INSUFFICIENT_RESOURCES,
-            MISSING_UNKNOWN_APN,
-            UNKNOWN_PDP_ADDRESS_TYPE,
-            USER_AUTHENTICATION,
-            ACTIVATION_REJECT_GGSN,
-            ACTIVATION_REJECT_UNSPECIFIED,
-            SERVICE_OPTION_NOT_SUPPORTED,
-            SERVICE_OPTION_NOT_SUBSCRIBED,
-            SERVICE_OPTION_OUT_OF_ORDER,
-            NSAPI_IN_USE,
-            REGULAR_DEACTIVATION,
-            QOS_NOT_ACCEPTED,
-            NETWORK_FAILURE,
-            UMTS_REACTIVATION_REQ,
-            FEATURE_NOT_SUPP,
-            TFT_SEMANTIC_ERROR,
-            TFT_SYTAX_ERROR,
-            UNKNOWN_PDP_CONTEXT,
-            FILTER_SEMANTIC_ERROR,
-            FILTER_SYTAX_ERROR,
-            PDP_WITHOUT_ACTIVE_TFT,
-            ACTIVATION_REJECTED_BCM_VIOLATION,
-            ONLY_IPV4_ALLOWED,
-            ONLY_IPV6_ALLOWED,
-            ONLY_SINGLE_BEARER_ALLOWED,
-            ESM_INFO_NOT_RECEIVED,
-            PDN_CONN_DOES_NOT_EXIST,
-            MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED,
-            COLLISION_WITH_NETWORK_INITIATED_REQUEST,
-            ONLY_IPV4V6_ALLOWED,
-            ONLY_NON_IP_ALLOWED,
-            UNSUPPORTED_QCI_VALUE,
-            BEARER_HANDLING_NOT_SUPPORTED,
-            ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED,
-            UNSUPPORTED_APN_IN_CURRENT_PLMN,
-            INVALID_TRANSACTION_ID,
-            MESSAGE_INCORRECT_SEMANTIC,
-            INVALID_MANDATORY_INFO,
-            MESSAGE_TYPE_UNSUPPORTED,
-            MSG_TYPE_NONCOMPATIBLE_STATE,
-            UNKNOWN_INFO_ELEMENT,
-            CONDITIONAL_IE_ERROR,
-            MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE,
-            PROTOCOL_ERRORS,
-            APN_TYPE_CONFLICT,
-            INVALID_PCSCF_ADDR,
-            INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN,
-            EMM_ACCESS_BARRED,
-            EMERGENCY_IFACE_ONLY,
-            IFACE_MISMATCH,
-            COMPANION_IFACE_IN_USE,
-            IP_ADDRESS_MISMATCH,
-            IFACE_AND_POL_FAMILY_MISMATCH,
-            EMM_ACCESS_BARRED_INFINITE_RETRY,
-            AUTH_FAILURE_ON_EMERGENCY_CALL,
-            INVALID_DNS_ADDR,
-            INVALID_PCSCF_OR_DNS_ADDRESS,
-            CALL_PREEMPT_BY_EMERGENCY_APN,
-            UE_INITIATED_DETACH_OR_DISCONNECT,
-            MIP_FA_REASON_UNSPECIFIED,
-            MIP_FA_ADMIN_PROHIBITED,
-            MIP_FA_INSUFFICIENT_RESOURCES,
-            MIP_FA_MOBILE_NODE_AUTHENTICATION_FAILURE,
-            MIP_FA_HOME_AGENT_AUTHENTICATION_FAILURE,
-            MIP_FA_REQUESTED_LIFETIME_TOO_LONG,
-            MIP_FA_MALFORMED_REQUEST,
-            MIP_FA_MALFORMED_REPLY,
-            MIP_FA_ENCAPSULATION_UNAVAILABLE,
-            MIP_FA_VJ_HEADER_COMPRESSION_UNAVAILABLE,
-            MIP_FA_REVERSE_TUNNEL_UNAVAILABLE,
-            MIP_FA_REVERSE_TUNNEL_IS_MANDATORY,
-            MIP_FA_DELIVERY_STYLE_NOT_SUPPORTED,
-            MIP_FA_MISSING_NAI,
-            MIP_FA_MISSING_HOME_AGENT,
-            MIP_FA_MISSING_HOME_ADDRESS,
-            MIP_FA_UNKNOWN_CHALLENGE,
-            MIP_FA_MISSING_CHALLENGE,
-            MIP_FA_STALE_CHALLENGE,
-            MIP_HA_REASON_UNSPECIFIED,
-            MIP_HA_ADMIN_PROHIBITED,
-            MIP_HA_INSUFFICIENT_RESOURCES,
-            MIP_HA_MOBILE_NODE_AUTHENTICATION_FAILURE,
-            MIP_HA_FOREIGN_AGENT_AUTHENTICATION_FAILURE,
-            MIP_HA_REGISTRATION_ID_MISMATCH,
-            MIP_HA_MALFORMED_REQUEST,
-            MIP_HA_UNKNOWN_HOME_AGENT_ADDRESS,
-            MIP_HA_REVERSE_TUNNEL_UNAVAILABLE,
-            MIP_HA_REVERSE_TUNNEL_IS_MANDATORY,
-            MIP_HA_ENCAPSULATION_UNAVAILABLE,
-            CLOSE_IN_PROGRESS,
-            NETWORK_INITIATED_TERMINATION,
-            MODEM_APP_PREEMPTED,
-            PDN_IPV4_CALL_DISALLOWED,
-            PDN_IPV4_CALL_THROTTLED,
-            PDN_IPV6_CALL_DISALLOWED,
-            PDN_IPV6_CALL_THROTTLED,
-            MODEM_RESTART,
-            PDP_PPP_NOT_SUPPORTED,
-            UNPREFERRED_RAT,
-            PHYSICAL_LINK_CLOSE_IN_PROGRESS,
-            APN_PENDING_HANDOVER,
-            PROFILE_BEARER_INCOMPATIBLE,
-            SIM_CARD_CHANGED,
-            LOW_POWER_MODE_OR_POWERING_DOWN,
-            APN_DISABLED,
-            MAX_PPP_INACTIVITY_TIMER_EXPIRED,
-            IPV6_ADDRESS_TRANSFER_FAILED,
-            TRAT_SWAP_FAILED,
-            EHRPD_TO_HRPD_FALLBACK,
-            MIP_CONFIG_FAILURE,
-            PDN_INACTIVITY_TIMER_EXPIRED,
-            MAX_IPV4_CONNECTIONS,
-            MAX_IPV6_CONNECTIONS,
-            APN_MISMATCH,
-            IP_VERSION_MISMATCH,
-            DUN_CALL_DISALLOWED,
-            INTERNAL_EPC_NONEPC_TRANSITION,
-            INTERFACE_IN_USE,
-            APN_DISALLOWED_ON_ROAMING,
-            APN_PARAMETERS_CHANGED,
-            NULL_APN_DISALLOWED,
-            THERMAL_MITIGATION,
-            DATA_SETTINGS_DISABLED,
-            DATA_ROAMING_SETTINGS_DISABLED,
-            DDS_SWITCHED,
-            FORBIDDEN_APN_NAME,
-            DDS_SWITCH_IN_PROGRESS,
-            CALL_DISALLOWED_IN_ROAMING,
-            NON_IP_NOT_SUPPORTED,
-            PDN_NON_IP_CALL_THROTTLED,
-            PDN_NON_IP_CALL_DISALLOWED,
-            CDMA_LOCK,
-            CDMA_INTERCEPT,
-            CDMA_REORDER,
-            CDMA_RELEASE_DUE_TO_SO_REJECTION,
-            CDMA_INCOMING_CALL,
-            CDMA_ALERT_STOP,
-            CHANNEL_ACQUISITION_FAILURE,
-            MAX_ACCESS_PROBE,
-            CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
-            NO_RESPONSE_FROM_BASE_STATION,
-            REJECTED_BY_BASE_STATION,
-            CONCURRENT_SERVICES_INCOMPATIBLE,
-            NO_CDMA_SERVICE,
-            RUIM_NOT_PRESENT,
-            CDMA_RETRY_ORDER,
-            ACCESS_BLOCK,
-            ACCESS_BLOCK_ALL,
-            IS707B_MAX_ACCESS_PROBES,
-            THERMAL_EMERGENCY,
-            CONCURRENT_SERVICES_NOT_ALLOWED,
-            INCOMING_CALL_REJECTED,
-            NO_SERVICE_ON_GATEWAY,
-            NO_GPRS_CONTEXT,
-            ILLEGAL_MS,
-            ILLEGAL_ME,
-            GPRS_SERVICES_AND_NON_GPRS_SERVICES_NOT_ALLOWED,
-            GPRS_SERVICES_NOT_ALLOWED,
-            MS_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK,
-            IMPLICITLY_DETACHED,
-            PLMN_NOT_ALLOWED,
-            LOCATION_AREA_NOT_ALLOWED,
-            GPRS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN,
-            PDP_DUPLICATE,
-            UE_RAT_CHANGE,
-            CONGESTION,
-            NO_PDP_CONTEXT_ACTIVATED,
-            ACCESS_CLASS_DSAC_REJECTION,
-            PDP_ACTIVATE_MAX_RETRY_FAILED,
-            RADIO_ACCESS_BEARER_FAILURE,
-            ESM_UNKNOWN_EPS_BEARER_CONTEXT,
-            DRB_RELEASED_BY_RRC,
-            CONNECTION_RELEASED,
-            EMM_DETACHED,
-            EMM_ATTACH_FAILED,
-            EMM_ATTACH_STARTED,
-            LTE_NAS_SERVICE_REQUEST_FAILED,
-            DUPLICATE_BEARER_ID,
-            ESM_COLLISION_SCENARIOS,
-            ESM_BEARER_DEACTIVATED_TO_SYNC_WITH_NETWORK,
-            ESM_NW_ACTIVATED_DED_BEARER_WITH_ID_OF_DEF_BEARER,
-            ESM_BAD_OTA_MESSAGE,
-            ESM_DOWNLOAD_SERVER_REJECTED_THE_CALL,
-            ESM_CONTEXT_TRANSFERRED_DUE_TO_IRAT,
-            DS_EXPLICIT_DEACTIVATION,
-            ESM_LOCAL_CAUSE_NONE,
-            LTE_THROTTLING_NOT_REQUIRED,
-            ACCESS_CONTROL_LIST_CHECK_FAILURE,
-            SERVICE_NOT_ALLOWED_ON_PLMN,
-            EMM_T3417_EXPIRED,
-            EMM_T3417_EXT_EXPIRED,
-            RRC_UPLINK_DATA_TRANSMISSION_FAILURE,
-            RRC_UPLINK_DELIVERY_FAILED_DUE_TO_HANDOVER,
-            RRC_UPLINK_CONNECTION_RELEASE,
-            RRC_UPLINK_RADIO_LINK_FAILURE,
-            RRC_UPLINK_ERROR_REQUEST_FROM_NAS,
-            RRC_CONNECTION_ACCESS_STRATUM_FAILURE,
-            RRC_CONNECTION_ANOTHER_PROCEDURE_IN_PROGRESS,
-            RRC_CONNECTION_ACCESS_BARRED,
-            RRC_CONNECTION_CELL_RESELECTION,
-            RRC_CONNECTION_CONFIG_FAILURE,
-            RRC_CONNECTION_TIMER_EXPIRED,
-            RRC_CONNECTION_LINK_FAILURE,
-            RRC_CONNECTION_CELL_NOT_CAMPED,
-            RRC_CONNECTION_SYSTEM_INTERVAL_FAILURE,
-            RRC_CONNECTION_REJECT_BY_NETWORK,
-            RRC_CONNECTION_NORMAL_RELEASE,
-            RRC_CONNECTION_RADIO_LINK_FAILURE,
-            RRC_CONNECTION_REESTABLISHMENT_FAILURE,
-            RRC_CONNECTION_OUT_OF_SERVICE_DURING_CELL_REGISTER,
-            RRC_CONNECTION_ABORT_REQUEST,
-            RRC_CONNECTION_SYSTEM_INFORMATION_BLOCK_READ_ERROR,
-            NETWORK_INITIATED_DETACH_WITH_AUTO_REATTACH,
-            NETWORK_INITIATED_DETACH_NO_AUTO_REATTACH,
-            ESM_PROCEDURE_TIME_OUT,
-            INVALID_CONNECTION_ID,
-            MAXIMIUM_NSAPIS_EXCEEDED,
-            INVALID_PRIMARY_NSAPI,
-            CANNOT_ENCODE_OTA_MESSAGE,
-            RADIO_ACCESS_BEARER_SETUP_FAILURE,
-            PDP_ESTABLISH_TIMEOUT_EXPIRED,
-            PDP_MODIFY_TIMEOUT_EXPIRED,
-            PDP_INACTIVE_TIMEOUT_EXPIRED,
-            PDP_LOWERLAYER_ERROR,
-            PDP_MODIFY_COLLISION,
-            MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED,
-            NAS_REQUEST_REJECTED_BY_NETWORK,
-            RRC_CONNECTION_INVALID_REQUEST,
-            RRC_CONNECTION_TRACKING_AREA_ID_CHANGED,
-            RRC_CONNECTION_RF_UNAVAILABLE,
-            RRC_CONNECTION_ABORTED_DUE_TO_IRAT_CHANGE,
-            RRC_CONNECTION_RELEASED_SECURITY_NOT_ACTIVE,
-            RRC_CONNECTION_ABORTED_AFTER_HANDOVER,
-            RRC_CONNECTION_ABORTED_AFTER_IRAT_CELL_CHANGE,
-            RRC_CONNECTION_ABORTED_DURING_IRAT_CELL_CHANGE,
-            IMSI_UNKNOWN_IN_HOME_SUBSCRIBER_SERVER,
-            IMEI_NOT_ACCEPTED,
-            EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED,
-            EPS_SERVICES_NOT_ALLOWED_IN_PLMN,
-            MSC_TEMPORARILY_NOT_REACHABLE,
-            CS_DOMAIN_NOT_AVAILABLE,
-            ESM_FAILURE,
-            MAC_FAILURE,
-            SYNCHRONIZATION_FAILURE,
-            UE_SECURITY_CAPABILITIES_MISMATCH,
-            SECURITY_MODE_REJECTED,
-            UNACCEPTABLE_NON_EPS_AUTHENTICATION,
-            CS_FALLBACK_CALL_ESTABLISHMENT_NOT_ALLOWED,
-            NO_EPS_BEARER_CONTEXT_ACTIVATED,
-            INVALID_EMM_STATE,
-            NAS_LAYER_FAILURE,
-            MULTIPLE_PDP_CALL_NOT_ALLOWED,
-            EMBMS_NOT_ENABLED,
-            IRAT_HANDOVER_FAILED,
-            EMBMS_REGULAR_DEACTIVATION,
-            TEST_LOOPBACK_REGULAR_DEACTIVATION,
-            LOWER_LAYER_REGISTRATION_FAILURE,
-            DATA_PLAN_EXPIRED,
-            UMTS_HANDOVER_TO_IWLAN,
-            EVDO_CONNECTION_DENY_BY_GENERAL_OR_NETWORK_BUSY,
-            EVDO_CONNECTION_DENY_BY_BILLING_OR_AUTHENTICATION_FAILURE,
-            EVDO_HDR_CHANGED,
-            EVDO_HDR_EXITED,
-            EVDO_HDR_NO_SESSION,
-            EVDO_USING_GPS_FIX_INSTEAD_OF_HDR_CALL,
-            EVDO_HDR_CONNECTION_SETUP_TIMEOUT,
-            FAILED_TO_ACQUIRE_COLOCATED_HDR,
-            OTASP_COMMIT_IN_PROGRESS,
-            NO_HYBRID_HDR_SERVICE,
-            HDR_NO_LOCK_GRANTED,
-            DBM_OR_SMS_IN_PROGRESS,
-            HDR_FADE,
-            HDR_ACCESS_FAILURE,
-            UNSUPPORTED_1X_PREV,
-            LOCAL_END,
-            NO_SERVICE,
-            FADE,
-            NORMAL_RELEASE,
-            ACCESS_ATTEMPT_ALREADY_IN_PROGRESS,
-            REDIRECTION_OR_HANDOFF_IN_PROGRESS,
-            EMERGENCY_MODE,
-            PHONE_IN_USE,
-            INVALID_MODE,
-            INVALID_SIM_STATE,
-            NO_COLLOCATED_HDR,
-            UE_IS_ENTERING_POWERSAVE_MODE,
-            DUAL_SWITCH,
-            PPP_TIMEOUT,
-            PPP_AUTH_FAILURE,
-            PPP_OPTION_MISMATCH,
-            PPP_PAP_FAILURE,
-            PPP_CHAP_FAILURE,
-            PPP_CLOSE_IN_PROGRESS,
-            LIMITED_TO_IPV4,
-            LIMITED_TO_IPV6,
-            VSNCP_TIMEOUT,
-            VSNCP_GEN_ERROR,
-            VSNCP_APN_UNATHORIZED,
-            VSNCP_PDN_LIMIT_EXCEEDED,
-            VSNCP_NO_PDN_GATEWAY_ADDRESS,
-            VSNCP_PDN_GATEWAY_UNREACHABLE,
-            VSNCP_PDN_GATEWAY_REJECT,
-            VSNCP_INSUFFICIENT_PARAMETERS,
-            VSNCP_RESOURCE_UNAVAILABLE,
-            VSNCP_ADMINISTRATIVELY_PROHIBITED,
-            VSNCP_PDN_ID_IN_USE,
-            VSNCP_SUBSCRIBER_LIMITATION,
-            VSNCP_PDN_EXISTS_FOR_THIS_APN,
-            VSNCP_RECONNECT_NOT_ALLOWED,
-            IPV6_PREFIX_UNAVAILABLE,
-            HANDOFF_PREFERENCE_CHANGED,
-            OEM_DCFAILCAUSE_1,
-            OEM_DCFAILCAUSE_2,
-            OEM_DCFAILCAUSE_3,
-            OEM_DCFAILCAUSE_4,
-            OEM_DCFAILCAUSE_5,
-            OEM_DCFAILCAUSE_6,
-            OEM_DCFAILCAUSE_7,
-            OEM_DCFAILCAUSE_8,
-            OEM_DCFAILCAUSE_9,
-            OEM_DCFAILCAUSE_10,
-            OEM_DCFAILCAUSE_11,
-            OEM_DCFAILCAUSE_12,
-            OEM_DCFAILCAUSE_13,
-            OEM_DCFAILCAUSE_14,
-            OEM_DCFAILCAUSE_15,
-            REGISTRATION_FAIL,
-            GPRS_REGISTRATION_FAIL,
-            SIGNAL_LOST,
-            PREF_RADIO_TECH_CHANGED,
-            RADIO_POWER_OFF,
-            TETHERED_CALL_ACTIVE,
-            ERROR_UNSPECIFIED,
-            UNKNOWN,
-            RADIO_NOT_AVAILABLE,
-            UNACCEPTABLE_NETWORK_PARAMETER,
-            CONNECTION_TO_DATACONNECTIONAC_BROKEN,
-            LOST_CONNECTION,
-            RESET_BY_FRAMEWORK
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface FailCause{}
-
     private static final Map<Integer, String> sFailCauseMap;
     static {
         sFailCauseMap = new HashMap<>();
@@ -1737,7 +1389,8 @@
      *
      * @hide
      */
-    public static boolean isRadioRestartFailure(@NonNull Context context, @FailCause int cause,
+    public static boolean isRadioRestartFailure(@NonNull Context context,
+                                                @DataFailureCause int cause,
                                                 int subId) {
         CarrierConfigManager configManager = (CarrierConfigManager)
                 context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -1765,7 +1418,8 @@
     }
 
     /** @hide */
-    public static boolean isPermanentFailure(@NonNull Context context, @FailCause int failCause,
+    public static boolean isPermanentFailure(@NonNull Context context,
+                                             @DataFailureCause int failCause,
                                              int subId) {
         synchronized (sPermanentFailureCache) {
 
@@ -1825,7 +1479,7 @@
     }
 
     /** @hide */
-    public static boolean isEventLoggable(@FailCause int dataFailCause) {
+    public static boolean isEventLoggable(@DataFailureCause int dataFailCause) {
         return (dataFailCause == OPERATOR_BARRED) || (dataFailCause == INSUFFICIENT_RESOURCES)
                 || (dataFailCause == UNKNOWN_PDP_ADDRESS_TYPE)
                 || (dataFailCause == USER_AUTHENTICATION)
@@ -1845,13 +1499,13 @@
     }
 
     /** @hide */
-    public static String toString(@FailCause int dataFailCause) {
+    public static String toString(@DataFailureCause int dataFailCause) {
         int cause = getFailCause(dataFailCause);
         return (cause == UNKNOWN) ? "UNKNOWN(" + dataFailCause + ")" : sFailCauseMap.get(cause);
     }
 
     /** @hide */
-    public static int getFailCause(@FailCause int failCause) {
+    public static int getFailCause(@DataFailureCause int failCause) {
         if (sFailCauseMap.containsKey(failCause)) {
             return failCause;
         } else {
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index da4da79..45deea2 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -243,6 +243,7 @@
     };
 
     private AtomicReference<IMbmsDownloadService> mService = new AtomicReference<>(null);
+    private ServiceConnection mServiceConnection;
     private final InternalDownloadSessionCallback mInternalCallback;
     private final Map<DownloadStatusListener, InternalDownloadStatusListener>
             mInternalDownloadStatusListeners = new HashMap<>();
@@ -318,56 +319,66 @@
     }
 
     private int bindAndInitialize() {
-        return MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION,
-                new ServiceConnection() {
-                    @Override
-                    public void onServiceConnected(ComponentName name, IBinder service) {
-                        IMbmsDownloadService downloadService =
-                                IMbmsDownloadService.Stub.asInterface(service);
-                        int result;
-                        try {
-                            result = downloadService.initialize(mSubscriptionId, mInternalCallback);
-                        } catch (RemoteException e) {
-                            Log.e(LOG_TAG, "Service died before initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        } catch (RuntimeException e) {
-                            Log.e(LOG_TAG, "Runtime exception during initialization");
-                            sendErrorToApp(
-                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
-                                    e.toString());
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        if (result == MbmsErrors.UNKNOWN) {
-                            // Unbind and throw an obvious error
-                            close();
-                            throw new IllegalStateException("Middleware must not return an"
-                                    + " unknown error code");
-                        }
-                        if (result != MbmsErrors.SUCCESS) {
-                            sendErrorToApp(result, "Error returned during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        try {
-                            downloadService.asBinder().linkToDeath(mDeathRecipient, 0);
-                        } catch (RemoteException e) {
-                            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
-                                    "Middleware lost during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        mService.set(downloadService);
-                    }
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                IMbmsDownloadService downloadService =
+                        IMbmsDownloadService.Stub.asInterface(service);
+                int result;
+                try {
+                    result = downloadService.initialize(mSubscriptionId, mInternalCallback);
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Service died before initialization");
+                    sIsInitialized.set(false);
+                    return;
+                } catch (RuntimeException e) {
+                    Log.e(LOG_TAG, "Runtime exception during initialization");
+                    sendErrorToApp(
+                            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                            e.toString());
+                    sIsInitialized.set(false);
+                    return;
+                }
+                if (result == MbmsErrors.UNKNOWN) {
+                    // Unbind and throw an obvious error
+                    close();
+                    throw new IllegalStateException("Middleware must not return an"
+                            + " unknown error code");
+                }
+                if (result != MbmsErrors.SUCCESS) {
+                    sendErrorToApp(result, "Error returned during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                try {
+                    downloadService.asBinder().linkToDeath(mDeathRecipient, 0);
+                } catch (RemoteException e) {
+                    sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                            "Middleware lost during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                mService.set(downloadService);
+            }
 
-                    @Override
-                    public void onServiceDisconnected(ComponentName name) {
-                        Log.w(LOG_TAG, "bindAndInitialize: Remote service disconnected");
-                        sIsInitialized.set(false);
-                        mService.set(null);
-                    }
-                });
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                Log.w(LOG_TAG, "bindAndInitialize: Remote service disconnected");
+                sIsInitialized.set(false);
+                mService.set(null);
+            }
+
+            @Override
+            public void onNullBinding(ComponentName name) {
+                Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null");
+                sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                        "Middleware service binding returned null");
+                sIsInitialized.set(false);
+                mService.set(null);
+                mContext.unbindService(this);
+            }
+        };
+        return MbmsUtils.startBinding(mContext, MBMS_DOWNLOAD_SERVICE_ACTION, mServiceConnection);
     }
 
     /**
@@ -965,17 +976,19 @@
     public void close() {
         try {
             IMbmsDownloadService downloadService = mService.get();
-            if (downloadService == null) {
+            if (downloadService == null || mServiceConnection == null) {
                 Log.i(LOG_TAG, "Service already dead");
                 return;
             }
             downloadService.dispose(mSubscriptionId);
+            mContext.unbindService(mServiceConnection);
         } catch (RemoteException e) {
             // Ignore
             Log.i(LOG_TAG, "Remote exception while disposing of service");
         } finally {
             mService.set(null);
             sIsInitialized.set(false);
+            mServiceConnection = null;
             mInternalCallback.stop();
         }
     }
diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java
index f1be31f..d54071f 100644
--- a/telephony/java/android/telephony/MbmsGroupCallSession.java
+++ b/telephony/java/android/telephony/MbmsGroupCallSession.java
@@ -80,6 +80,7 @@
     };
 
     private InternalGroupCallSessionCallback mInternalCallback;
+    private ServiceConnection mServiceConnection;
     private Set<GroupCall> mKnownActiveGroupCalls = new ArraySet<>();
 
     private final Context mContext;
@@ -163,7 +164,7 @@
     public void close() {
         try {
             IMbmsGroupCallService groupCallService = mService.get();
-            if (groupCallService == null) {
+            if (groupCallService == null || mServiceConnection == null) {
                 // Ignore and return, assume already disposed.
                 return;
             }
@@ -172,11 +173,13 @@
                 s.getCallback().stop();
             }
             mKnownActiveGroupCalls.clear();
+            mContext.unbindService(mServiceConnection);
         } catch (RemoteException e) {
             // Ignore for now
         } finally {
             mService.set(null);
             sIsInitialized.set(false);
+            mServiceConnection = null;
             mInternalCallback.stop();
         }
     }
@@ -244,59 +247,69 @@
     }
 
     private int bindAndInitialize() {
-        return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION,
-                new ServiceConnection() {
-                    @Override
-                    public void onServiceConnected(ComponentName name, IBinder service) {
-                        IMbmsGroupCallService groupCallService =
-                                IMbmsGroupCallService.Stub.asInterface(service);
-                        int result;
-                        try {
-                            result = groupCallService.initialize(mInternalCallback,
-                                    mSubscriptionId);
-                        } catch (RemoteException e) {
-                            Log.e(LOG_TAG, "Service died before initialization");
-                            mInternalCallback.onError(
-                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
-                                    e.toString());
-                            sIsInitialized.set(false);
-                            return;
-                        } catch (RuntimeException e) {
-                            Log.e(LOG_TAG, "Runtime exception during initialization");
-                            mInternalCallback.onError(
-                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
-                                    e.toString());
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        if (result == MbmsErrors.UNKNOWN) {
-                            // Unbind and throw an obvious error
-                            close();
-                            throw new IllegalStateException("Middleware must not return"
-                                    + " an unknown error code");
-                        }
-                        if (result != MbmsErrors.SUCCESS) {
-                            mInternalCallback.onError(result,
-                                    "Error returned during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        try {
-                            groupCallService.asBinder().linkToDeath(mDeathRecipient, 0);
-                        } catch (RemoteException e) {
-                            mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
-                                    "Middleware lost during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        mService.set(groupCallService);
-                    }
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                IMbmsGroupCallService groupCallService =
+                        IMbmsGroupCallService.Stub.asInterface(service);
+                int result;
+                try {
+                    result = groupCallService.initialize(mInternalCallback,
+                            mSubscriptionId);
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Service died before initialization");
+                    mInternalCallback.onError(
+                            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                            e.toString());
+                    sIsInitialized.set(false);
+                    return;
+                } catch (RuntimeException e) {
+                    Log.e(LOG_TAG, "Runtime exception during initialization");
+                    mInternalCallback.onError(
+                            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                            e.toString());
+                    sIsInitialized.set(false);
+                    return;
+                }
+                if (result == MbmsErrors.UNKNOWN) {
+                    // Unbind and throw an obvious error
+                    close();
+                    throw new IllegalStateException("Middleware must not return"
+                            + " an unknown error code");
+                }
+                if (result != MbmsErrors.SUCCESS) {
+                    mInternalCallback.onError(result,
+                            "Error returned during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                try {
+                    groupCallService.asBinder().linkToDeath(mDeathRecipient, 0);
+                } catch (RemoteException e) {
+                    mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                            "Middleware lost during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                mService.set(groupCallService);
+            }
 
-                    @Override
-                    public void onServiceDisconnected(ComponentName name) {
-                        sIsInitialized.set(false);
-                        mService.set(null);
-                    }
-                });
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                sIsInitialized.set(false);
+                mService.set(null);
+            }
+
+            @Override
+            public void onNullBinding(ComponentName name) {
+                Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null");
+                mInternalCallback.onError(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                        "Middleware service binding returned null");
+                sIsInitialized.set(false);
+                mService.set(null);
+                mContext.unbindService(this);
+            }
+        };
+        return MbmsUtils.startBinding(mContext, MBMS_GROUP_CALL_SERVICE_ACTION, mServiceConnection);
     }
 }
diff --git a/telephony/java/android/telephony/MbmsStreamingSession.java b/telephony/java/android/telephony/MbmsStreamingSession.java
index cd465d2..3fbbc03 100644
--- a/telephony/java/android/telephony/MbmsStreamingSession.java
+++ b/telephony/java/android/telephony/MbmsStreamingSession.java
@@ -82,6 +82,7 @@
     };
 
     private InternalStreamingSessionCallback mInternalCallback;
+    private ServiceConnection mServiceConnection;
     private Set<StreamingService> mKnownActiveStreamingServices = new ArraySet<>();
 
     private final Context mContext;
@@ -168,7 +169,7 @@
     public void close() {
         try {
             IMbmsStreamingService streamingService = mService.get();
-            if (streamingService == null) {
+            if (streamingService == null || mServiceConnection == null) {
                 // Ignore and return, assume already disposed.
                 return;
             }
@@ -177,11 +178,13 @@
                 s.getCallback().stop();
             }
             mKnownActiveStreamingServices.clear();
+            mContext.unbindService(mServiceConnection);
         } catch (RemoteException e) {
             // Ignore for now
         } finally {
             mService.set(null);
             sIsInitialized.set(false);
+            mServiceConnection = null;
             mInternalCallback.stop();
         }
     }
@@ -286,59 +289,69 @@
     }
 
     private int bindAndInitialize() {
-        return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION,
-                new ServiceConnection() {
-                    @Override
-                    public void onServiceConnected(ComponentName name, IBinder service) {
-                        IMbmsStreamingService streamingService =
-                                IMbmsStreamingService.Stub.asInterface(service);
-                        int result;
-                        try {
-                            result = streamingService.initialize(mInternalCallback,
-                                    mSubscriptionId);
-                        } catch (RemoteException e) {
-                            Log.e(LOG_TAG, "Service died before initialization");
-                            sendErrorToApp(
-                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
-                                    e.toString());
-                            sIsInitialized.set(false);
-                            return;
-                        } catch (RuntimeException e) {
-                            Log.e(LOG_TAG, "Runtime exception during initialization");
-                            sendErrorToApp(
-                                    MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
-                                    e.toString());
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        if (result == MbmsErrors.UNKNOWN) {
-                            // Unbind and throw an obvious error
-                            close();
-                            throw new IllegalStateException("Middleware must not return"
-                                    + " an unknown error code");
-                        }
-                        if (result != MbmsErrors.SUCCESS) {
-                            sendErrorToApp(result, "Error returned during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        try {
-                            streamingService.asBinder().linkToDeath(mDeathRecipient, 0);
-                        } catch (RemoteException e) {
-                            sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
-                                    "Middleware lost during initialization");
-                            sIsInitialized.set(false);
-                            return;
-                        }
-                        mService.set(streamingService);
-                    }
+        mServiceConnection = new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName name, IBinder service) {
+                IMbmsStreamingService streamingService =
+                        IMbmsStreamingService.Stub.asInterface(service);
+                int result;
+                try {
+                    result = streamingService.initialize(mInternalCallback,
+                            mSubscriptionId);
+                } catch (RemoteException e) {
+                    Log.e(LOG_TAG, "Service died before initialization");
+                    sendErrorToApp(
+                            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                            e.toString());
+                    sIsInitialized.set(false);
+                    return;
+                } catch (RuntimeException e) {
+                    Log.e(LOG_TAG, "Runtime exception during initialization");
+                    sendErrorToApp(
+                            MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+                            e.toString());
+                    sIsInitialized.set(false);
+                    return;
+                }
+                if (result == MbmsErrors.UNKNOWN) {
+                    // Unbind and throw an obvious error
+                    close();
+                    throw new IllegalStateException("Middleware must not return"
+                            + " an unknown error code");
+                }
+                if (result != MbmsErrors.SUCCESS) {
+                    sendErrorToApp(result, "Error returned during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                try {
+                    streamingService.asBinder().linkToDeath(mDeathRecipient, 0);
+                } catch (RemoteException e) {
+                    sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                            "Middleware lost during initialization");
+                    sIsInitialized.set(false);
+                    return;
+                }
+                mService.set(streamingService);
+            }
 
-                    @Override
-                    public void onServiceDisconnected(ComponentName name) {
-                        sIsInitialized.set(false);
-                        mService.set(null);
-                    }
-                });
+            @Override
+            public void onServiceDisconnected(ComponentName name) {
+                sIsInitialized.set(false);
+                mService.set(null);
+            }
+
+            @Override
+            public void onNullBinding(ComponentName name) {
+                Log.w(LOG_TAG, "bindAndInitialize: Remote service returned null");
+                sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST,
+                        "Middleware service binding returned null");
+                sIsInitialized.set(false);
+                mService.set(null);
+                mContext.unbindService(this);
+            }
+        };
+        return MbmsUtils.startBinding(mContext, MBMS_STREAMING_SERVICE_ACTION, mServiceConnection);
     }
 
     private void sendErrorToApp(int errorCode, String message) {
diff --git a/telephony/java/android/telephony/MmsManager.java b/telephony/java/android/telephony/MmsManager.java
new file mode 100644
index 0000000..4bcf046
--- /dev/null
+++ b/telephony/java/android/telephony/MmsManager.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.app.ActivityThread;
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+import com.android.internal.telephony.IMms;
+
+/**
+ * Manages MMS operations such as sending multimedia messages.
+ * Get this object by calling the static method {@link #getInstance()}.
+ * @hide
+ */
+public class MmsManager {
+    private static final String TAG = "MmsManager";
+
+    /** Singleton object constructed during class initialization. */
+    private static final MmsManager sInstance = new MmsManager();
+
+    /**
+     * Get the MmsManager singleton instance.
+     *
+     * @return the {@link MmsManager} singleton instance.
+     */
+    public static MmsManager getInstance() {
+        return sInstance;
+    }
+
+    /**
+     * Send an MMS message
+     *
+     * @param subId the subscription id
+     * @param contentUri the content Uri from which the message pdu will be read
+     * @param locationUrl the optional location url where message should be sent to
+     * @param configOverrides the carrier-specific messaging configuration values to override for
+     *                        sending the message.
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is broadcast when the message
+     *                   is successfully sent, or failed
+     */
+    public void sendMultimediaMessage(int subId, Uri contentUri, String locationUrl,
+            Bundle configOverrides, PendingIntent sentIntent) {
+        try {
+            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms == null) {
+                return;
+            }
+
+            iMms.sendMessage(subId, ActivityThread.currentPackageName(), contentUri,
+                    locationUrl, configOverrides, sentIntent);
+        } catch (RemoteException e) {
+            // Ignore it
+        }
+    }
+
+    /**
+     * Download an MMS message from carrier by a given location URL
+     *
+     * @param subId the subscription id
+     * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
+     *  from the MMS WAP push notification
+     * @param contentUri the content uri to which the downloaded pdu will be written
+     * @param configOverrides the carrier-specific messaging configuration values to override for
+     *  downloading the message.
+     * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is downloaded, or the download is failed
+     * @throws IllegalArgumentException if locationUrl or contentUri is empty
+     */
+    public void downloadMultimediaMessage(int subId, String locationUrl, Uri contentUri,
+            Bundle configOverrides, PendingIntent downloadedIntent) {
+        try {
+            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms == null) {
+                return;
+            }
+            iMms.downloadMessage(subId, ActivityThread.currentPackageName(),
+                    locationUrl, contentUri, configOverrides, downloadedIntent);
+        } catch (RemoteException e) {
+            // Ignore it
+        }
+    }
+
+    /**
+     * Get carrier-dependent configuration values.
+     *
+     * @param subId the subscription id
+     * @return bundle key/values pairs of configuration values
+     */
+    public Bundle getCarrierConfigValues(int subId) {
+        try {
+            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
+            if (iMms != null) {
+                return iMms.getCarrierConfigValues(subId);
+            }
+        } catch (RemoteException ex) {
+            // ignore it
+        }
+        return null;
+    }
+}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index a76b8da..3e02871 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -24,8 +24,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.TransportType;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 1ffed25..c2028f9 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Binder;
 import android.os.Build;
@@ -27,6 +28,10 @@
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
+import android.telephony.Annotation.SrvccState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
 
@@ -179,7 +184,8 @@
     public static final int LISTEN_CELL_INFO = 0x00000400;
 
     /**
-     * Listen for {@link PreciseCallState.State} of ringing, background and foreground calls.
+     * Listen for {@link android.telephony.Annotation.PreciseCallStates} of ringing,
+     * background and foreground calls.
      *
      * @hide
      */
@@ -366,6 +372,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_CALL_EMERGENCY_NUMBER           = 0x10000000;
 
@@ -378,6 +385,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     public static final int LISTEN_OUTGOING_SMS_EMERGENCY_NUMBER            = 0x20000000;
 
@@ -564,7 +572,7 @@
      * privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
      * passed as an argument.
      */
-    public void onCallStateChanged(@TelephonyManager.CallState int state, String phoneNumber) {
+    public void onCallStateChanged(@CallState int state, String phoneNumber) {
         // default implementation empty
     }
 
@@ -770,7 +778,7 @@
      * @hide
      */
     @SystemApi
-    public void onSrvccStateChanged(@TelephonyManager.SrvccState int srvccState) {
+    public void onSrvccStateChanged(@SrvccState int srvccState) {
 
     }
 
@@ -788,7 +796,7 @@
      * @hide
      */
     @SystemApi
-    public void onVoiceActivationStateChanged(@TelephonyManager.SimActivationState int state) {
+    public void onVoiceActivationStateChanged(@SimActivationState int state) {
     }
 
     /**
@@ -804,7 +812,7 @@
      * @param state is the current SIM data activation state
      * @hide
      */
-    public void onDataActivationStateChanged(@TelephonyManager.SimActivationState int state) {
+    public void onDataActivationStateChanged(@SimActivationState int state) {
     }
 
     /**
@@ -869,6 +877,7 @@
      *                              to.
      * @hide
      */
+    @SystemApi
     public void onOutgoingEmergencyCall(@NonNull EmergencyNumber placedEmergencyNumber) {
         // default implementation empty
     }
@@ -879,6 +888,7 @@
      * @param sentEmergencyNumber the emergency number {@link EmergencyNumber} the SMS is sent to.
      * @hide
      */
+    @SystemApi
     public void onOutgoingEmergencySms(@NonNull EmergencyNumber sentEmergencyNumber) {
         // default implementation empty
     }
@@ -959,7 +969,7 @@
      * @hide
      */
     @SystemApi
-    public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+    public void onRadioPowerStateChanged(@RadioPowerState int state) {
         // default implementation empty
     }
 
@@ -1226,7 +1236,7 @@
                     () -> mExecutor.execute(() -> psl.onPhoneCapabilityChanged(capability)));
         }
 
-        public void onRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state) {
+        public void onRadioPowerStateChanged(@RadioPowerState int state) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index e1763ab..4273f5a 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -19,8 +19,8 @@
 import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
index 701a375..9f75332 100644
--- a/telephony/java/android/telephony/PreciseCallState.java
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -23,6 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.PreciseCallStates;
 import android.telephony.DisconnectCause;
 import android.telephony.PreciseDisconnectCause;
 
@@ -41,29 +42,13 @@
  *   <li>Precise background call state.
  * </ul>
  *
- * @see android.telephony.TelephonyManager.CallState which contains generic call states.
+ * @see android.telephony.Annotation.CallState which contains generic call states.
  *
  * @hide
  */
 @SystemApi
 public final class PreciseCallState implements Parcelable {
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"PRECISE_CALL_STATE_"},
-            value = {
-                    PRECISE_CALL_STATE_NOT_VALID,
-                    PRECISE_CALL_STATE_IDLE,
-                    PRECISE_CALL_STATE_ACTIVE,
-                    PRECISE_CALL_STATE_HOLDING,
-                    PRECISE_CALL_STATE_DIALING,
-                    PRECISE_CALL_STATE_ALERTING,
-                    PRECISE_CALL_STATE_INCOMING,
-                    PRECISE_CALL_STATE_WAITING,
-                    PRECISE_CALL_STATE_DISCONNECTED,
-                    PRECISE_CALL_STATE_DISCONNECTING})
-    public @interface State {}
-
     /** Call state is not valid (Not received a call state). */
     public static final int PRECISE_CALL_STATE_NOT_VALID =      -1;
     /** Call state: No activity. */
@@ -85,9 +70,9 @@
     /** Call state: Disconnecting. */
     public static final int PRECISE_CALL_STATE_DISCONNECTING =  8;
 
-    private @State int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private @State int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
-    private @State int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+    private @PreciseCallStates int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
     private int mDisconnectCause = DisconnectCause.NOT_VALID;
     private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
 
@@ -97,8 +82,9 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseCallState(@State int ringingCall, @State int foregroundCall,
-                            @State int backgroundCall, int disconnectCause,
+    public PreciseCallState(@PreciseCallStates int ringingCall,
+                            @PreciseCallStates int foregroundCall,
+                            @PreciseCallStates int backgroundCall, int disconnectCause,
                             int preciseDisconnectCause) {
         mRingingCallState = ringingCall;
         mForegroundCallState = foregroundCall;
@@ -131,21 +117,21 @@
     /**
      * Returns the precise ringing call state.
      */
-    public @State int getRingingCallState() {
+    public @PreciseCallStates int getRingingCallState() {
         return mRingingCallState;
     }
 
     /**
      * Returns the precise foreground call state.
      */
-    public @State int getForegroundCallState() {
+    public @PreciseCallStates int getForegroundCallState() {
         return mForegroundCallState;
     }
 
     /**
      * Returns the precise background call state.
      */
-    public @State int getBackgroundCallState() {
+    public @PreciseCallStates int getBackgroundCallState() {
         return mBackgroundCallState;
     }
 
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 90d443a..257d634 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -23,6 +23,10 @@
 import android.net.LinkProperties;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.DataFailureCause;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.data.ApnSetting;
 
 import java.util.Objects;
@@ -47,10 +51,10 @@
 @SystemApi
 public final class PreciseDataConnectionState implements Parcelable {
 
-    private @TelephonyManager.DataState int mState = TelephonyManager.DATA_UNKNOWN;
-    private @TelephonyManager.NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-    private @DataFailCause.FailCause int mFailCause = DataFailCause.NONE;
-    private @ApnSetting.ApnType int mAPNTypes = ApnSetting.TYPE_NONE;
+    private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
+    private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+    private @DataFailureCause int mFailCause = DataFailCause.NONE;
+    private @ApnType int mAPNTypes = ApnSetting.TYPE_NONE;
     private String mAPN = "";
     private LinkProperties mLinkProperties = null;
 
@@ -60,11 +64,11 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public PreciseDataConnectionState(@TelephonyManager.DataState int state,
-                                      @TelephonyManager.NetworkType int networkType,
-                                      @ApnSetting.ApnType int apnTypes, String apn,
+    public PreciseDataConnectionState(@DataState int state,
+                                      @NetworkType int networkType,
+                                      @ApnType int apnTypes, String apn,
                                       LinkProperties linkProperties,
-                                      @DataFailCause.FailCause int failCause) {
+                                      @DataFailureCause int failCause) {
         mState = state;
         mNetworkType = networkType;
         mAPNTypes = apnTypes;
@@ -99,7 +103,7 @@
      * Returns the state of data connection that supported the apn types returned by
      * {@link #getDataConnectionApnTypeBitMask()}
      */
-    public @TelephonyManager.DataState int getDataConnectionState() {
+    public @DataState int getDataConnectionState() {
         return mState;
     }
 
@@ -107,7 +111,7 @@
      * Returns the network type associated with this data connection.
      * @hide
      */
-    public @TelephonyManager.NetworkType int getDataConnectionNetworkType() {
+    public @NetworkType int getDataConnectionNetworkType() {
         return mNetworkType;
     }
 
@@ -115,7 +119,7 @@
      * Returns the data connection APN types supported by this connection and triggers
      * {@link PreciseDataConnectionState} change.
      */
-    public @ApnSetting.ApnType int getDataConnectionApnTypeBitMask() {
+    public @ApnType int getDataConnectionApnTypeBitMask() {
         return mAPNTypes;
     }
 
@@ -139,7 +143,7 @@
     /**
      * Returns data connection fail cause, in case there was a failure.
      */
-    public @DataFailCause.FailCause int getDataConnectionFailCause() {
+    public @Annotation.DataFailureCause int getDataConnectionFailCause() {
         return mFailCause;
     }
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a985a6b..8587be7 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -29,6 +29,8 @@
 import android.os.Parcelable;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RilRadioTechnology;
 import android.telephony.NetworkRegistrationInfo.Domain;
 import android.telephony.NetworkRegistrationInfo.NRState;
 import android.text.TextUtils;
@@ -154,32 +156,6 @@
      */
     public static final int DUPLEX_MODE_TDD = 2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = { "RIL_RADIO_TECHNOLOGY_" },
-            value = {
-                    RIL_RADIO_TECHNOLOGY_UNKNOWN,
-                    RIL_RADIO_TECHNOLOGY_GPRS,
-                    RIL_RADIO_TECHNOLOGY_EDGE,
-                    RIL_RADIO_TECHNOLOGY_UMTS,
-                    RIL_RADIO_TECHNOLOGY_IS95A,
-                    RIL_RADIO_TECHNOLOGY_IS95B,
-                    RIL_RADIO_TECHNOLOGY_1xRTT,
-                    RIL_RADIO_TECHNOLOGY_EVDO_0,
-                    RIL_RADIO_TECHNOLOGY_EVDO_A,
-                    RIL_RADIO_TECHNOLOGY_HSDPA,
-                    RIL_RADIO_TECHNOLOGY_HSUPA,
-                    RIL_RADIO_TECHNOLOGY_HSPA,
-                    RIL_RADIO_TECHNOLOGY_EVDO_B,
-                    RIL_RADIO_TECHNOLOGY_EHRPD,
-                    RIL_RADIO_TECHNOLOGY_LTE,
-                    RIL_RADIO_TECHNOLOGY_HSPAP,
-                    RIL_RADIO_TECHNOLOGY_GSM,
-                    RIL_RADIO_TECHNOLOGY_TD_SCDMA,
-                    RIL_RADIO_TECHNOLOGY_IWLAN,
-                    RIL_RADIO_TECHNOLOGY_LTE_CA,
-                    RIL_RADIO_TECHNOLOGY_NR})
-    public @interface RilRadioTechnology {}
     /**
      * Available radio technologies for GSM, UMTS and CDMA.
      * Duplicates the constants from hardware/radio/include/ril.h
@@ -1617,7 +1593,7 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
-    public @TelephonyManager.NetworkType int getDataNetworkType() {
+    public @NetworkType int getDataNetworkType() {
         final NetworkRegistrationInfo iwlanRegInfo = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
         final NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
@@ -1644,7 +1620,7 @@
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
-    public @TelephonyManager.NetworkType int getVoiceNetworkType() {
+    public @NetworkType int getVoiceNetworkType() {
         final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
         if (regState != null) {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 8c14cb4..71fcf23 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -27,13 +27,11 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
-import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.CursorWindow;
 import android.net.Uri;
-import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -45,7 +43,6 @@
 import android.util.Log;
 
 import com.android.internal.telephony.IIntegerConsumer;
-import com.android.internal.telephony.IMms;
 import com.android.internal.telephony.ISms;
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.SmsRawData;
@@ -357,6 +354,68 @@
                 true /* persistMessage*/, ActivityThread.currentPackageName());
     }
 
+    /**
+     * Send a text based SMS with messaging options.
+     *
+     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
+     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
+     * suitable default subscription could be found. In this case, if {@code sentIntent} is
+     * non-null, then the {@link PendingIntent} will be sent with an error code
+     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
+     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
+     * where this operation may fail.
+     * </p>
+     *
+     * @param destinationAddress the address to send the message to
+     * @param scAddress is the service center address or null to use
+     *  the current default SMSC
+     * @param text the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is successfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK</code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param priority Priority level of the message
+     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
+     *  ---------------------------------
+     *  PRIORITY      | Level of Priority
+     *  ---------------------------------
+     *      '00'      |     Normal
+     *      '01'      |     Interactive
+     *      '10'      |     Urgent
+     *      '11'      |     Emergency
+     *  ----------------------------------
+     *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
+     * @param expectMore is a boolean to indicate the sending messages through same link or not.
+     * @param validityPeriod Validity Period of the message in mins.
+     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
+     *  Validity Period(Minimum) -> 5 mins
+     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
+     *  Any Other values included Negative considered as Invalid Validity Period of the message.
+     *
+     * @throws IllegalArgumentException if destinationAddress or text are empty
+     * {@hide}
+     */
+    @UnsupportedAppUsage
+    public void sendTextMessage(
+            String destinationAddress, String scAddress, String text,
+            PendingIntent sentIntent, PendingIntent deliveryIntent,
+            int priority, boolean expectMore, int validityPeriod) {
+        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
+                true /* persistMessage*/, priority, expectMore, validityPeriod);
+    }
+
     private void sendTextMessageInternal(String destinationAddress, String scAddress,
             String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
             boolean persistMessage, String packageName) {
@@ -455,109 +514,6 @@
                 false /* persistMessage */, ActivityThread.currentPackageName());
     }
 
-    /**
-     * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the SMS being sent on the subscription associated with logical
-     * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
-     * correct subscription.
-     * </p>
-     *
-     * @param persistMessage whether to persist the sent message in the SMS app. the caller must be
-     * the Phone process if set to false.
-     *
-     * @hide
-     */
-    public void sendTextMessageWithSelfPermissions(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-
-        if (TextUtils.isEmpty(text)) {
-            throw new IllegalArgumentException("Invalid message body");
-        }
-
-        try {
-            ISms iSms = getISmsServiceOrThrow();
-            iSms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(),
-                    destinationAddress,
-                    scAddress, text, sentIntent, deliveryIntent, persistMessage);
-        } catch (RemoteException ex) {
-            notifySmsGenericError(sentIntent);
-        }
-    }
-
-    /**
-     * Send a text based SMS with messaging options.
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param destinationAddress the address to send the message to
-     * @param scAddress is the service center address or null to use
-     *  the current default SMSC
-     * @param text the body of the message to send
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed.
-     *  The result code will be <code>Activity.RESULT_OK</code> for success,
-     *  or one of these errors:<br>
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
-     *  The per-application based SMS control checks sentIntent. If sentIntent
-     *  is NULL the caller will be checked against all unknown applications,
-     *  which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is delivered to the recipient.  The
-     *  raw pdu of the status report is in the extended data ("pdu").
-     * @param priority Priority level of the message
-     *  Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1
-     *  ---------------------------------
-     *  PRIORITY      | Level of Priority
-     *  ---------------------------------
-     *      '00'      |     Normal
-     *      '01'      |     Interactive
-     *      '10'      |     Urgent
-     *      '11'      |     Emergency
-     *  ----------------------------------
-     *  Any Other values included Negative considered as Invalid Priority Indicator of the message.
-     * @param expectMore is a boolean to indicate the sending messages through same link or not.
-     * @param validityPeriod Validity Period of the message in mins.
-     *  Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1.
-     *  Validity Period(Minimum) -> 5 mins
-     *  Validity Period(Maximum) -> 635040 mins(i.e.63 weeks).
-     *  Any Other values included Negative considered as Invalid Validity Period of the message.
-     *
-     * @throws IllegalArgumentException if destinationAddress or text are empty
-     * {@hide}
-     */
-    @UnsupportedAppUsage
-    public void sendTextMessage(
-            String destinationAddress, String scAddress, String text,
-            PendingIntent sentIntent, PendingIntent deliveryIntent,
-            int priority, boolean expectMore, int validityPeriod) {
-        sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
-                true /* persistMessage*/, priority, expectMore, validityPeriod);
-    }
-
     private void sendTextMessageInternal(
             String destinationAddress, String scAddress, String text,
             PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage,
@@ -1078,37 +1034,6 @@
     }
 
     /**
-     * Send a multi-part text based SMS without writing it into the SMS Provider.
-     *
-     * <p>Requires Permission:
-     * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
-     * privileges.
-     * </p>
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use the Telephony
-     * framework and will never trigger an SMS disambiguation dialog. If this method is called on a
-     * device that has multiple active subscriptions, this {@link SmsManager} instance has been
-     * created with {@link #getDefault()}, and no user-defined default subscription is defined, the
-     * subscription ID associated with this message will be INVALID, which will result in the SMS
-     * being sent on the subscription associated with logical slot 0. Use
-     * {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the correct
-     * subscription.
-     * </p>
-     *
-     * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList,
-     * ArrayList, int, boolean, int)
-     * @hide
-     **/
-    public void sendMultipartTextMessageWithoutPersisting(
-            String destinationAddress, String scAddress, List<String> parts,
-            List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
-            int priority, boolean expectMore, int validityPeriod) {
-        sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
-                deliveryIntents, false /* persistMessage*/, priority, expectMore,
-                validityPeriod);
-    }
-
-    /**
      * Send a data based SMS to a specific application port.
      *
      * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -1180,45 +1105,6 @@
     }
 
     /**
-     * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
-     * for internal use only.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the SMS being sent on the subscription associated with logical
-     * slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the SMS is sent on the
-     * correct subscription.
-     * </p>
-     *
-     * @hide
-     */
-    public void sendDataMessageWithSelfPermissions(
-            String destinationAddress, String scAddress, short destinationPort,
-            byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
-        if (TextUtils.isEmpty(destinationAddress)) {
-            throw new IllegalArgumentException("Invalid destinationAddress");
-        }
-
-        if (data == null || data.length == 0) {
-            throw new IllegalArgumentException("Invalid message data");
-        }
-
-        try {
-            ISms iSms = getISmsServiceOrThrow();
-            iSms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
-                    ActivityThread.currentPackageName(), destinationAddress, scAddress,
-                    destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
-        } catch (RemoteException e) {
-            Log.e(TAG, "sendDataMessageWithSelfPermissions: Couldn't send SMS - Exception: "
-                    + e.getMessage());
-            notifySmsGenericError(sentIntent);
-        }
-    }
-
-    /**
      * Get the SmsManager associated with the default subscription id. The instance will always be
      * associated with the default subscription id, even if the default subscription id changes.
      *
@@ -1650,100 +1536,6 @@
 
     /**
      * Enable reception of cell broadcast (SMS-CB) messages with the given
-     * message identifier and RAN type. The RAN type specify this message ID
-     * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
-     * enable the same message identifier, they must both disable it for the device to stop
-     * receiving those messages. All received messages will be broadcast in an
-     * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
-     * Note: This call is blocking, callers may want to avoid calling it from
-     * the main thread of an application.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType the message format as defined in {@link SmsCbMessage]
-     * @return true if successful, false otherwise
-     * @see #disableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean enableCellBroadcast(int messageIdentifier,
-            @android.telephony.SmsCbMessage.MessageFormat int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iSms = getISmsService();
-            if (iSms != null) {
-                // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
-                // the default phone internally.
-                success = iSms.enableCellBroadcastForSubscriber(getSubscriptionId(),
-                        messageIdentifier, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Disable reception of cell broadcast (SMS-CB) messages with the given
-     * message identifier and RAN type. The RAN type specify this message ID
-     * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
-     * enable the same message identifier, they must both disable it for the
-     * device to stop receiving those messages.
-     * Note: This call is blocking, callers may want to avoid calling it from
-     * the main thread of an application.
-     *
-     * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
-     * applications or the Telephony framework and will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
-     * or C.R1001-G (3GPP2)
-     * @param ranType the message format as defined in {@link SmsCbMessage}
-     * @return true if successful, false otherwise
-     *
-     * @see #enableCellBroadcast(int, int)
-     *
-     * {@hide}
-     */
-    public boolean disableCellBroadcast(int messageIdentifier,
-            @android.telephony.SmsCbMessage.MessageFormat int ranType) {
-        boolean success = false;
-
-        try {
-            ISms iSms = getISmsService();
-            if (iSms != null) {
-                // If getSubscriptionId() returns INVALID or an inactive subscription, we will use
-                // the default phone internally.
-                success = iSms.disableCellBroadcastForSubscriber(getSubscriptionId(),
-                        messageIdentifier, ranType);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-
-        return success;
-    }
-
-    /**
-     * Enable reception of cell broadcast (SMS-CB) messages with the given
      * message identifier range and RAN type. The RAN type specifies if this message ID
      * belongs to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
      * the same message identifier, they must both disable it for the device to stop
@@ -2144,9 +1936,6 @@
     @SystemApi
     static public final int RESULT_REQUEST_NOT_SUPPORTED = 24;
 
-
-    static private final String PHONE_PACKAGE_NAME = "com.android.phone";
-
     /**
      * Send an MMS message
      *
@@ -2173,17 +1962,8 @@
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        try {
-            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-
-            iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
+        MmsManager.getInstance().sendMultimediaMessage(getSubscriptionId(), contentUri,
                     locationUrl, configOverrides, sentIntent);
-        } catch (RemoteException e) {
-            // Ignore it
-        }
     }
 
     /**
@@ -2216,16 +1996,8 @@
         if (contentUri == null) {
             throw new IllegalArgumentException("Uri contentUri null");
         }
-        try {
-            final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms == null) {
-                return;
-            }
-            iMms.downloadMessage(getSubscriptionId(), ActivityThread.currentPackageName(),
-                    locationUrl, contentUri, configOverrides, downloadedIntent);
-        } catch (RemoteException e) {
-            // Ignore it
-        }
+        MmsManager.getInstance().downloadMultimediaMessage(getSubscriptionId(), locationUrl,
+                contentUri, configOverrides, downloadedIntent);
     }
 
     // MMS send/download failure result codes
@@ -2243,434 +2015,17 @@
     /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
     public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
 
-    /**
-     * Import a text message into system's SMS store
-     *
-     * Only default SMS apps can import SMS
-     *
-     * @param address the destination(source) address of the sent(received) message
-     * @param type the type of the message
-     * @param text the message text
-     * @param timestampMillis the message timestamp in milliseconds
-     * @param seen if the message is seen
-     * @param read if the message is read
-     * @return the message URI, null if failed
-     * @hide
-     */
-    public Uri importTextMessage(String address, int type, String text, long timestampMillis,
-            boolean seen, boolean read) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.importTextMessage(ActivityThread.currentPackageName(),
-                        address, type, text, timestampMillis, seen, read);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
     /** Represents the received SMS message for importing {@hide} */
     public static final int SMS_TYPE_INCOMING = 0;
     /** Represents the sent SMS message for importing {@hide} */
     public static final int SMS_TYPE_OUTGOING = 1;
 
-    /**
-     * Import a multimedia message into system's MMS store. Only the following PDU type is
-     * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
-     *
-     * Only default SMS apps can import MMS
-     *
-     * @param contentUri the content uri from which to read the PDU of the message to import
-     * @param messageId the optional message id. Use null if not specifying
-     * @param timestampSecs the optional message timestamp. Use -1 if not specifying
-     * @param seen if the message is seen
-     * @param read if the message is read
-     * @return the message URI, null if failed
-     * @throws IllegalArgumentException if pdu is empty
-     * {@hide}
-     */
-    public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
-            boolean seen, boolean read) {
-        if (contentUri == null) {
-            throw new IllegalArgumentException("Uri contentUri null");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
-                        contentUri, messageId, timestampSecs, seen, read);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Delete a system stored SMS or MMS message
-     *
-     * Only default SMS apps can delete system stored SMS and MMS messages
-     *
-     * @param messageUri the URI of the stored message
-     * @return true if deletion is successful, false otherwise
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public boolean deleteStoredMessage(Uri messageUri) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Delete a system stored SMS or MMS thread
-     *
-     * Only default SMS apps can delete system stored SMS and MMS conversations
-     *
-     * @param conversationId the ID of the message conversation
-     * @return true if deletion is successful, false otherwise
-     * {@hide}
-     */
-    public boolean deleteStoredConversation(long conversationId) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.deleteStoredConversation(
-                        ActivityThread.currentPackageName(), conversationId);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Update the status properties of a system stored SMS or MMS message, e.g.
-     * the read status of a message, etc.
-     *
-     * @param messageUri the URI of the stored message
-     * @param statusValues a list of status properties in key-value pairs to update
-     * @return true if update is successful, false otherwise
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
-                        messageUri, statusValues);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
     /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
     public static final String MESSAGE_STATUS_SEEN = "seen";
     /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
     public static final String MESSAGE_STATUS_READ = "read";
 
     /**
-     * Archive or unarchive a stored conversation
-     *
-     * @param conversationId the ID of the message conversation
-     * @param archived true to archive the conversation, false to unarchive
-     * @return true if update is successful, false otherwise
-     * {@hide}
-     */
-    public boolean archiveStoredConversation(long conversationId, boolean archived) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
-                        conversationId, archived);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
-     * Add a text message draft to system SMS store
-     *
-     * Only default SMS apps can add SMS draft
-     *
-     * @param address the destination address of message
-     * @param text the body of the message to send
-     * @return the URI of the stored draft message
-     * {@hide}
-     */
-    public Uri addTextMessageDraft(String address, String text) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Add a multimedia message draft to system MMS store
-     *
-     * Only default SMS apps can add MMS draft
-     *
-     * @param contentUri the content uri from which to read the PDU data of the draft MMS
-     * @return the URI of the stored draft message
-     * @throws IllegalArgumentException if pdu is empty
-     * {@hide}
-     */
-    public Uri addMultimediaMessageDraft(Uri contentUri) {
-        if (contentUri == null) {
-            throw new IllegalArgumentException("Uri contentUri null");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
-                        contentUri);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
-    }
-
-    /**
-     * Send a system stored text message.
-     *
-     * You can only send a failed text message or a draft text message.
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param scAddress is the service center address or null to use the current default SMSC
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed.
-     *  The result code will be <code>Activity.RESULT_OK</code> for success,
-     *  or one of these errors:<br>
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *  <code>RESULT_ERROR_NULL_PDU</code><br>
-     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
-     *  the extra "errorCode" containing a radio technology specific value,
-     *  generally only useful for troubleshooting.<br>
-     *  The per-application based SMS control checks sentIntent. If sentIntent
-     *  is NULL the caller will be checked against all unknown applications,
-     *  which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is delivered to the recipient.  The
-     *  raw pdu of the status report is in the extended data ("pdu").
-     *
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
-            PendingIntent deliveryIntent) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        resolveSubscriptionForOperation(new SubscriptionResolverResult() {
-            @Override
-            public void onSuccess(int subId) {
-                try {
-                    ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendStoredText(subId, ActivityThread.currentPackageName(), messageUri,
-                            scAddress, sentIntent, deliveryIntent);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
-                            + e.getMessage());
-                    notifySmsGenericError(sentIntent);
-                }
-            }
-            @Override
-            public void onFailure() {
-                notifySmsErrorNoDefaultSet(context, sentIntent);
-            }
-        });
-    }
-
-    /**
-     * Send a system stored multi-part text message.
-     *
-     * You can only send a failed text message or a draft text message.
-     * The provided <code>PendingIntent</code> lists should match the part number of the
-     * divided text of the stored message by using <code>divideMessage</code>
-     *
-     * <p class="note"><strong>Note:</strong> If {@link #getDefault()} is used to instantiate this
-     * manager on a multi-SIM device, this operation may fail sending the SMS message because no
-     * suitable default subscription could be found. In this case, if {@code sentIntent} is
-     * non-null, then the {@link PendingIntent} will be sent with an error code
-     * {@code RESULT_ERROR_GENERIC_FAILURE} and an extra string {@code "noDefault"} containing the
-     * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions
-     * where this operation may fail.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param scAddress is the service center address or null to use
-     *   the current default SMSC
-     * @param sentIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been sent.
-     *   The result code will be <code>Activity.RESULT_OK</code> for success,
-     *   or one of these errors:<br>
-     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
-     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
-     *   <code>RESULT_ERROR_NULL_PDU</code><br>
-     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
-     *   the extra "errorCode" containing a radio technology specific value,
-     *   generally only useful for troubleshooting.<br>
-     *   The per-application based SMS control checks sentIntent. If sentIntent
-     *   is NULL the caller will be checked against all unknown applications,
-     *   which cause smaller number of SMS to be sent in checking period.
-     * @param deliveryIntents if not null, an <code>ArrayList</code> of
-     *   <code>PendingIntent</code>s (one for each message part) that is
-     *   broadcast when the corresponding message part has been delivered
-     *   to the recipient.  The raw pdu of the status report is in the
-     *   extended data ("pdu").
-     *
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
-            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        final Context context = ActivityThread.currentApplication().getApplicationContext();
-        resolveSubscriptionForOperation(new SubscriptionResolverResult() {
-            @Override
-            public void onSuccess(int subId) {
-                try {
-                    ISms iSms = getISmsServiceOrThrow();
-                    iSms.sendStoredMultipartText(subId, ActivityThread.currentPackageName(),
-                            messageUri, scAddress, sentIntents, deliveryIntents);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "sendStoredTextMessage: Couldn't send SMS - Exception: "
-                            + e.getMessage());
-                    notifySmsGenericError(sentIntents);
-                }
-            }
-            @Override
-            public void onFailure() {
-                notifySmsErrorNoDefaultSet(context, sentIntents);
-            }
-        });
-    }
-
-    /**
-     * Send a system stored MMS message
-     *
-     * This is used for sending a previously sent, but failed-to-send, message or
-     * for sending a text message that has been stored as a draft.
-     *
-     * <p class="note"><strong>Note:</strong> This method will never trigger an SMS disambiguation
-     * dialog. If this method is called on a device that has multiple active subscriptions, this
-     * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
-     * default subscription is defined, the subscription ID associated with this message will be
-     * INVALID, which will result in the operation being completed on the subscription associated
-     * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
-     * operation is performed on the correct subscription.
-     * </p>
-     *
-     * @param messageUri the URI of the stored message
-     * @param configOverrides the carrier-specific messaging configuration values to override for
-     *  sending the message.
-     * @param sentIntent if not NULL this <code>PendingIntent</code> is
-     *  broadcast when the message is successfully sent, or failed
-     * @throws IllegalArgumentException if messageUri is empty
-     * {@hide}
-     */
-    public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
-            PendingIntent sentIntent) {
-        if (messageUri == null) {
-            throw new IllegalArgumentException("Empty message URI");
-        }
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                iMms.sendStoredMessage(
-                        getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
-                        configOverrides, sentIntent);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
-     *
-     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
-     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
-     * automatically
-     *
-     * This flag can only be changed by default SMS apps
-     *
-     * @param enabled Whether to enable message auto persisting
-     * {@hide}
-     */
-    public void setAutoPersisting(boolean enabled) {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-    }
-
-    /**
-     * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
-     *
-     * When this flag is on, all SMS/MMS sent/received are stored by system automatically
-     * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
-     * automatically
-     *
-     * @return the current value of the auto persist flag
-     * {@hide}
-     */
-    public boolean getAutoPersisting() {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.getAutoPersisting();
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return false;
-    }
-
-    /**
      * Get carrier-dependent configuration values.
      *
      * <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
@@ -2686,15 +2041,7 @@
      * @return bundle key/values pairs of configuration values
      */
     public Bundle getCarrierConfigValues() {
-        try {
-            IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
-            if (iMms != null) {
-                return iMms.getCarrierConfigValues(getSubscriptionId());
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return null;
+        return MmsManager.getInstance().getCarrierConfigValues(getSubscriptionId());
     }
 
     /**
@@ -2780,38 +2127,38 @@
     }
 
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The prefixes is a list of prefix {@code String} separated by this delimiter.
      * @hide
      */
     public static final String REGEX_PREFIX_DELIMITER = ",";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The success status to be added into the intent to be sent to the calling package.
      * @hide
      */
     public static final int RESULT_STATUS_SUCCESS = 0;
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * The timeout status to be added into the intent to be sent to the calling package.
      * @hide
      */
     public static final int RESULT_STATUS_TIMEOUT = 1;
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * Intent extra key of the retrieved SMS message as a {@code String}.
      * @hide
      */
     public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * Intent extra key of SMS retriever status, which indicates whether the request for the
      * coming SMS message is SUCCESS or TIMEOUT
      * @hide
      */
     public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
     /**
-     * @see #createAppSpecificSmsTokenWithPackageInfo().
+     * @see #createAppSpecificSmsTokenWithPackageInfo(String, PendingIntent).
      * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
      * @hide
      */
@@ -2861,74 +2208,6 @@
         }
     }
 
-    /**
-     * Filters a bundle to only contain MMS config variables.
-     *
-     * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
-     * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the
-     * supplied bundle.
-     *
-     * @param config a Bundle that contains MMS config variables and possibly more.
-     * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above.
-     * @hide
-     */
-    public static Bundle getMmsConfig(BaseBundle config) {
-        Bundle filtered = new Bundle();
-        filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID,
-                config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID));
-        filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED,
-                config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
-                config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO,
-                config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO));
-        filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED,
-                config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
-                config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
-        filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
-                config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
-        filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
-                config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
-        filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
-                config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
-        filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
-        filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
-        filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
-        filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT));
-        filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS));
-        filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS));
-        filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
-                config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
-        filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
-                config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
-        filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
-                config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
-        filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH,
-                config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH));
-        filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
-                config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
-        filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME,
-                config.getString(MMS_CONFIG_UA_PROF_TAG_NAME));
-        filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT));
-        filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL));
-        filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS));
-        filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
-                config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
-        filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX));
-        filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
-                config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
-        filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
-                config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
-        return filtered;
-    }
-
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"SMS_CATEGORY_"},
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index dcd35fd..a893288 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telephony.TelephonyManager.NetworkType;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.euicc.EuiccManager;
 import android.telephony.ims.ImsMmTelManager;
 import android.util.DisplayMetrics;
@@ -2101,13 +2101,26 @@
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public static boolean isValidSlotIndex(int slotIndex) {
-        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getSimCount();
+        return slotIndex >= 0 && slotIndex < TelephonyManager.getDefault().getMaxPhoneCount();
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public static boolean isValidPhoneId(int phoneId) {
-        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount();
+        return phoneId >= 0 && phoneId < TelephonyManager.getDefault().getMaxPhoneCount();
+    }
+
+    /**
+     * When getPhoneCount and getMaxPhoneCount return different value, isValidPhoneId being true
+     * doesn't mean the phoneId has a corresponding active slot / logical modem. If a DSDS capable
+     * device is in single SIM mode, phoneId=1 is valid but not active.
+     *
+     * TODO: b/139642279 combine with SubscriptionManager#isValidPhoneId when phone objects
+     * are dynamically allocated instead of always based on getMaxPhoneCount.
+     * @hide
+     */
+    public static boolean isActivePhoneId(int slotIndex) {
+        return slotIndex < TelephonyManager.getDefault().getPhoneCount();
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4f276bc..f3215d4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -63,6 +63,12 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.CallState;
+import android.telephony.Annotation.DataState;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.RadioPowerState;
+import android.telephony.Annotation.SimActivationState;
 import android.telephony.VisualVoicemailService.VisualVoicemailTask;
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
@@ -254,17 +260,6 @@
      */
     public static final int UNINITIALIZED_CARD_ID = -2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"SRVCC_STATE_"},
-            value = {
-                    SRVCC_STATE_HANDOVER_NONE,
-                    SRVCC_STATE_HANDOVER_STARTED,
-                    SRVCC_STATE_HANDOVER_COMPLETED,
-                    SRVCC_STATE_HANDOVER_FAILED,
-                    SRVCC_STATE_HANDOVER_CANCELED})
-    public @interface SrvccState {}
-
     private final Context mContext;
     private final int mSubId;
     @UnsupportedAppUsage
@@ -404,7 +399,7 @@
      * TODO: b/139642279 publicize and rename.
      * @hide
      */
-    public static int getMaxPhoneCount() {
+    public int getMaxPhoneCount() {
         // TODO: b/139642279 when turning on this feature, remove dependency of
         // PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE and always return result based on
         // PROPERTY_MAX_ACTIVE_MODEMS.
@@ -413,9 +408,9 @@
         if (rebootRequired.equals("false")) {
             // If no reboot is required, return max possible active modems.
             return SystemProperties.getInt(
-                    TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getDefault().getPhoneCount());
+                    TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS, getPhoneCount());
         } else {
-            return getDefault().getPhoneCount();
+            return getPhoneCount();
         }
     }
 
@@ -2449,7 +2444,14 @@
      * @return the lowercase 2 character ISO-3166 country code, or empty string if not available.
      */
     public String getNetworkCountryIso() {
-        return getNetworkCountryIso(getPhoneId());
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony == null) return "";
+            return telephony.getNetworkCountryIsoForPhone(getPhoneId(),
+                    null /* no permission check */);
+        } catch (RemoteException ex) {
+            return "";
+        }
     }
 
     /**
@@ -2475,11 +2477,12 @@
     @SystemApi
     @TestApi
     @NonNull
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getNetworkCountryIso(int slotIndex) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony == null) return "";
-            return telephony.getNetworkCountryIsoForPhone(slotIndex);
+            return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName());
         } catch (RemoteException ex) {
             return "";
         }
@@ -2538,33 +2541,6 @@
     /** Max network type number. Update as new types are added. Don't add negative types. {@hide} */
     public static final int MAX_NETWORK_TYPE = NETWORK_TYPE_NR;
 
-    /** @hide */
-    @IntDef({
-            NETWORK_TYPE_UNKNOWN,
-            NETWORK_TYPE_GPRS,
-            NETWORK_TYPE_EDGE,
-            NETWORK_TYPE_UMTS,
-            NETWORK_TYPE_CDMA,
-            NETWORK_TYPE_EVDO_0,
-            NETWORK_TYPE_EVDO_A,
-            NETWORK_TYPE_1xRTT,
-            NETWORK_TYPE_HSDPA,
-            NETWORK_TYPE_HSUPA,
-            NETWORK_TYPE_HSPA,
-            NETWORK_TYPE_IDEN,
-            NETWORK_TYPE_EVDO_B,
-            NETWORK_TYPE_LTE,
-            NETWORK_TYPE_EHRPD,
-            NETWORK_TYPE_HSPAP,
-            NETWORK_TYPE_GSM,
-            NETWORK_TYPE_TD_SCDMA,
-            NETWORK_TYPE_IWLAN,
-            NETWORK_TYPE_LTE_CA,
-            NETWORK_TYPE_NR,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface NetworkType{}
-
     /**
      * Return the current data network type.
      *
@@ -4611,17 +4587,6 @@
     @SystemApi
     public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4;
 
-    /** @hide */
-    @IntDef({
-            SIM_ACTIVATION_STATE_UNKNOWN,
-            SIM_ACTIVATION_STATE_ACTIVATING,
-            SIM_ACTIVATION_STATE_ACTIVATED,
-            SIM_ACTIVATION_STATE_DEACTIVATED,
-            SIM_ACTIVATION_STATE_RESTRICTED
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface SimActivationState{}
-
      /**
       * Sets the voice activation state
       *
@@ -5006,15 +4971,6 @@
      */
     public static final int CALL_STATE_OFFHOOK = 2;
 
-    /** @hide */
-    @IntDef(prefix = { "CALL_STATE_" }, value = {
-            CALL_STATE_IDLE,
-            CALL_STATE_RINGING,
-            CALL_STATE_OFFHOOK
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface CallState{}
-
     /**
      * Returns the state of all calls on the device.
      * <p>
@@ -5095,17 +5051,6 @@
      */
     public static final int DATA_ACTIVITY_DORMANT = 0x00000004;
 
-    /** @hide */
-    @IntDef(prefix = {"DATA_"}, value = {
-        DATA_ACTIVITY_NONE,
-        DATA_ACTIVITY_IN,
-        DATA_ACTIVITY_OUT,
-        DATA_ACTIVITY_INOUT,
-        DATA_ACTIVITY_DORMANT,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface DataActivityType{}
-
     /**
      * Returns a constant indicating the type of activity on a data connection
      * (cellular).
@@ -8321,15 +8266,6 @@
         return false;
     }
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(prefix = {"RADIO_POWER_"},
-            value = {RADIO_POWER_OFF,
-                    RADIO_POWER_ON,
-                    RADIO_POWER_UNAVAILABLE,
-            })
-    public @interface RadioPowerState {}
-
     /**
      * Radio explicitly powered off (e.g, airplane mode).
      * @hide
@@ -11443,7 +11379,7 @@
      *
      * @hide
      */
-    public boolean isDataEnabledForApn(@ApnSetting.ApnType int apnType) {
+    public boolean isDataEnabledForApn(@ApnType int apnType) {
         String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
         try {
             ITelephony service = getITelephony();
@@ -11464,7 +11400,7 @@
      *
      * @hide
      */
-    public boolean isApnMetered(@ApnSetting.ApnType int apnType) {
+    public boolean isApnMetered(@ApnType int apnType) {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
diff --git a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java
index 5f2f75d..02429b5 100644
--- a/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java
+++ b/telephony/java/android/telephony/cdma/CdmaSmsCbProgramData.java
@@ -16,12 +16,19 @@
 
 package android.telephony.cdma;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
- * CDMA Service Category Program Data from SCPT teleservice SMS.
+ * CDMA Service Category Program Data from SCPT (Service Category Programming Teleservice) SMS,
+ * as defined in 3GPP2 C.S0015-B section 4.5.19.
+ * <p>
  * The CellBroadcastReceiver app receives an Intent with action
  * {@link android.provider.Telephony.Sms.Intents#SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION}
  * containing an array of these objects to update its list of cell broadcast service categories
@@ -29,6 +36,7 @@
  *
  * {@hide}
  */
+@SystemApi
 public final class CdmaSmsCbProgramData implements Parcelable {
 
     /** Delete the specified service category from the list of enabled categories. */
@@ -40,40 +48,83 @@
     /** Clear all service categories from the list of enabled categories. */
     public static final int OPERATION_CLEAR_CATEGORIES  = 2;
 
-    /** Alert option: no alert. */
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"OPERATION_"},
+            value = {
+                    OPERATION_DELETE_CATEGORY,
+                    OPERATION_ADD_CATEGORY,
+                    OPERATION_CLEAR_CATEGORIES,
+            })
+    public @interface Operation {}
+
+    // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1
+    /** Indicates a presidential-level alert */
+    public static final int CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT  = 0x1000;
+
+    /** Indicates an extreme threat to life and property */
+    public static final int CATEGORY_CMAS_EXTREME_THREAT            = 0x1001;
+
+    /** Indicates an severe threat to life and property */
+    public static final int CATEGORY_CMAS_SEVERE_THREAT             = 0x1002;
+
+    /** Indicates an AMBER child abduction emergency */
+    public static final int CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003;
+
+    /** Indicates a CMAS test message */
+    public static final int CATEGORY_CMAS_TEST_MESSAGE              = 0x1004;
+
+    /** The last reserved value of a CMAS service category according to 3GPP C.R1001 table
+     * 9.3.3-1. */
+    public static final int CATEGORY_CMAS_LAST_RESERVED_VALUE       = 0x10ff;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CATEGORY_"},
+            value = {
+                    CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT,
+                    CATEGORY_CMAS_EXTREME_THREAT,
+                    CATEGORY_CMAS_SEVERE_THREAT,
+                    CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY,
+                    CATEGORY_CMAS_TEST_MESSAGE,
+                    CATEGORY_CMAS_LAST_RESERVED_VALUE,
+            })
+    public @interface Category {}
+
+    /** Alert option: no alert. @hide */
     public static final int ALERT_OPTION_NO_ALERT               = 0;
 
-    /** Alert option: default alert. */
+    /** Alert option: default alert. @hide */
     public static final int ALERT_OPTION_DEFAULT_ALERT          = 1;
 
-    /** Alert option: vibrate alert once. */
+    /** Alert option: vibrate alert once. @hide */
     public static final int ALERT_OPTION_VIBRATE_ONCE           = 2;
 
-    /** Alert option: vibrate alert - repeat. */
+    /** Alert option: vibrate alert - repeat. @hide */
     public static final int ALERT_OPTION_VIBRATE_REPEAT         = 3;
 
-    /** Alert option: visual alert once. */
+    /** Alert option: visual alert once. @hide */
     public static final int ALERT_OPTION_VISUAL_ONCE            = 4;
 
-    /** Alert option: visual alert - repeat. */
+    /** Alert option: visual alert - repeat. @hide */
     public static final int ALERT_OPTION_VISUAL_REPEAT          = 5;
 
-    /** Alert option: low-priority alert once. */
+    /** Alert option: low-priority alert once. @hide */
     public static final int ALERT_OPTION_LOW_PRIORITY_ONCE      = 6;
 
-    /** Alert option: low-priority alert - repeat. */
+    /** Alert option: low-priority alert - repeat. @hide */
     public static final int ALERT_OPTION_LOW_PRIORITY_REPEAT    = 7;
 
-    /** Alert option: medium-priority alert once. */
+    /** Alert option: medium-priority alert once. @hide */
     public static final int ALERT_OPTION_MED_PRIORITY_ONCE      = 8;
 
-    /** Alert option: medium-priority alert - repeat. */
+    /** Alert option: medium-priority alert - repeat. @hide */
     public static final int ALERT_OPTION_MED_PRIORITY_REPEAT    = 9;
 
-    /** Alert option: high-priority alert once. */
+    /** Alert option: high-priority alert once. @hide */
     public static final int ALERT_OPTION_HIGH_PRIORITY_ONCE     = 10;
 
-    /** Alert option: high-priority alert - repeat. */
+    /** Alert option: high-priority alert - repeat. @hide */
     public static final int ALERT_OPTION_HIGH_PRIORITY_REPEAT   = 11;
 
     /** Service category operation (add/delete/clear). */
@@ -94,9 +145,12 @@
     /** Name of service category. */
     private final String mCategoryName;
 
-    /** Create a new CdmaSmsCbProgramData object with the specified values. */
-    public CdmaSmsCbProgramData(int operation, int category, int language, int maxMessages,
-            int alertOption, @NonNull String categoryName) {
+    /**
+     * Create a new CdmaSmsCbProgramData object with the specified values.
+     * @hide
+     */
+    public CdmaSmsCbProgramData(@Operation int operation, @Category int category, int language,
+            int maxMessages, int alertOption, @NonNull String categoryName) {
         mOperation = operation;
         mCategory = category;
         mLanguage = language;
@@ -105,7 +159,10 @@
         mCategoryName = categoryName;
     }
 
-    /** Create a new CdmaSmsCbProgramData object from a Parcel. */
+    /**
+     * Create a new CdmaSmsCbProgramData object from a Parcel.
+     * @hide
+     */
     CdmaSmsCbProgramData(Parcel in) {
         mOperation = in.readInt();
         mCategory = in.readInt();
@@ -133,23 +190,28 @@
 
     /**
      * Returns the service category operation, e.g. {@link #OPERATION_ADD_CATEGORY}.
-     * @return one of the {@code OPERATION_*} values
+     *
+     * @return the service category operation
      */
-    public int getOperation() {
+    public @Operation int getOperation() {
         return mOperation;
     }
 
     /**
-     * Returns the CDMA service category to modify.
+     * Returns the CDMA service category to modify. See 3GPP2 C.S0015-B section 3.4.3.2 for more
+     * information on the service category. Currently only CMAS service categories 0x1000 through
+     * 0x10FF are supported.
+     *
      * @return a 16-bit CDMA service category value
      */
-    public int getCategory() {
+    public @Category int getCategory() {
         return mCategory;
     }
 
     /**
      * Returns the CDMA language code for this service category.
      * @return one of the language values defined in BearerData.LANGUAGE_*
+     * @hide
      */
     public int getLanguage() {
         return mLanguage;
@@ -158,6 +220,7 @@
     /**
      * Returns the maximum number of messages to store for this service category.
      * @return the maximum number of messages to store for this service category
+     * @hide
      */
     public int getMaxMessages() {
         return mMaxMessages;
@@ -166,6 +229,7 @@
     /**
      * Returns the service category alert option, e.g. {@link #ALERT_OPTION_DEFAULT_ALERT}.
      * @return one of the {@code ALERT_OPTION_*} values
+     * @hide
      */
     public int getAlertOption() {
         return mAlertOption;
@@ -174,6 +238,7 @@
     /**
      * Returns the service category name, in the language specified by {@link #getLanguage()}.
      * @return an optional service category name
+     * @hide
      */
     @NonNull
     public String getCategoryName() {
@@ -196,7 +261,10 @@
         return 0;
     }
 
-    /** Creator for unparcelling objects. */
+    /**
+     * Creator for unparcelling objects.
+     */
+    @NonNull
     public static final Parcelable.Creator<CdmaSmsCbProgramData>
             CREATOR = new Parcelable.Creator<CdmaSmsCbProgramData>() {
         @Override
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 116c0512..2161dcb 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -26,6 +26,8 @@
 import android.os.Parcelable;
 import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
+import android.telephony.Annotation.ApnType;
+import android.telephony.Annotation.NetworkType;
 import android.telephony.Rlog;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -109,23 +111,6 @@
     /** APN type for MCX (Mission Critical Service) where X can be PTT/Video/Data */
     public static final int TYPE_MCX = ApnTypes.MCX;
 
-    /** @hide */
-    @IntDef(flag = true, prefix = { "TYPE_" }, value = {
-        TYPE_DEFAULT,
-        TYPE_MMS,
-        TYPE_SUPL,
-        TYPE_DUN,
-        TYPE_HIPRI,
-        TYPE_FOTA,
-        TYPE_IMS,
-        TYPE_CBS,
-        TYPE_IA,
-        TYPE_EMERGENCY,
-        TYPE_MCX
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface ApnType {}
-
     // Possible values for authentication types.
     /** No authentication type. */
     public static final int AUTH_TYPE_NONE = 0;
@@ -1425,7 +1410,7 @@
      *
      * @hide
      */
-    public boolean canSupportNetworkType(@TelephonyManager.NetworkType int networkType) {
+    public boolean canSupportNetworkType(@NetworkType int networkType) {
         // Do a special checking for GSM. In reality, GSM is a voice only network type and can never
         // be used for data. We allow it here because in some DSDS corner cases, on the non-DDS
         // sub, modem reports data rat unknown. In that case if voice is GSM and this APN supports
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index 9170e88..49625bb 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -24,8 +24,8 @@
 import android.net.LinkAddress;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.DataFailureCause;
 import android.telephony.DataFailCause;
-import android.telephony.DataFailCause.FailCause;
 import android.telephony.data.ApnSetting.ProtocolType;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -67,7 +67,7 @@
     /** Indicates the data connection is active with physical link up. */
     public static final int LINK_STATUS_ACTIVE = 2;
 
-    private final @FailCause int mCause;
+    private final @DataFailureCause int mCause;
     private final int mSuggestedRetryTime;
     private final int mId;
     private final @LinkStatus int mLinkStatus;
@@ -103,7 +103,7 @@
      *
      * @removed Use the {@link Builder()} instead.
      */
-    public DataCallResponse(@FailCause int cause, int suggestedRetryTime, int id,
+    public DataCallResponse(@DataFailureCause int cause, int suggestedRetryTime, int id,
                             @LinkStatus int linkStatus,
                             @ProtocolType int protocolType, @Nullable String interfaceName,
                             @Nullable List<LinkAddress> addresses,
@@ -150,7 +150,7 @@
     /**
      * @return Data call fail cause. {@link DataFailCause#NONE} indicates no error.
      */
-    @FailCause
+    @DataFailureCause
     public int getCause() { return mCause; }
 
     /**
@@ -314,7 +314,7 @@
      * </code></pre>
      */
     public static final class Builder {
-        private @FailCause int mCause;
+        private @DataFailureCause int mCause;
 
         private int mSuggestedRetryTime;
 
@@ -348,7 +348,7 @@
          * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error.
          * @return The same instance of the builder.
          */
-        public @NonNull Builder setCause(@FailCause int cause) {
+        public @NonNull Builder setCause(@DataFailureCause int cause) {
             mCause = cause;
             return this;
         }
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 0d79ec9..30c209b 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -25,8 +25,8 @@
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Annotation.ApnType;
 import android.telephony.TelephonyManager.NetworkTypeBitMask;
-import android.telephony.data.ApnSetting.ApnType;
 import android.telephony.data.ApnSetting.AuthType;
 import android.text.TextUtils;
 
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 0e1751d..e793979 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -27,8 +27,8 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.telephony.AccessNetworkConstants.AccessNetworkType;
+import android.telephony.Annotation.ApnType;
 import android.telephony.Rlog;
-import android.telephony.data.ApnSetting.ApnType;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -133,7 +133,7 @@
          * service.
          *
          * @param apnTypes APN types of the qualified networks. This must be a bitmask combination
-         * of {@link ApnSetting.ApnType}.
+         * of {@link ApnType}.
          * @param qualifiedNetworkTypes List of network types which are qualified for data
          * connection setup for {@link @apnType} in the preferred order. Each element in the list
          * is a {@link AccessNetworkType}. An empty list indicates no networks are qualified
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 19d0724..1666265 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.TestApi;
 import android.hardware.radio.V1_4.EmergencyNumberSource;
 import android.hardware.radio.V1_4.EmergencyServiceCategory;
 import android.os.Parcel;
@@ -184,6 +185,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final int EMERGENCY_NUMBER_SOURCE_TEST =  1 << 5;
     /** Bit-field which indicates the number is from the modem config. */
     public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 866e936..4d90579 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -302,7 +302,7 @@
      * operator's MCC (Mobile Country Code).
      * @see android.telephony.TelephonyManager#getNetworkCountryIso
      */
-    String getNetworkCountryIsoForPhone(int phoneId);
+    String getNetworkCountryIsoForPhone(int phoneId, String callingPkg);
 
     /**
      * Returns the neighboring cell information of the device.
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index fe76b7c..d7a7af1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -93,6 +93,10 @@
     void notifyActiveDataSubIdChanged(int activeDataSubId);
     void notifyRadioPowerStateChanged(in int phoneId, in int subId, in int state);
     void notifyEmergencyNumberList(in int phoneId, in int subId);
+    void notifyOutgoingEmergencyCall(in int phoneId, in int subId,
+            in EmergencyNumber emergencyNumber);
+    void notifyOutgoingEmergencySms(in int phoneId, in int subId,
+            in EmergencyNumber emergencyNumber);
     void notifyCallQualityChanged(in CallQuality callQuality, int phoneId, int subId,
             int callNetworkType);
     void notifyImsDisconnectCause(int subId, in ImsReasonInfo imsReasonInfo);
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index f10398f..f4eae8e 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -40,7 +40,6 @@
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
 import android.telephony.Rlog;
-import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
@@ -1045,9 +1044,6 @@
      */
     @UnsupportedAppUsage
     public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
-        if (SmsManager.getDefault().getAutoPersisting()) {
-            return true;
-        }
         return !isDefaultSmsApplication(context, packageName);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
index 3440c65..2787b24 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -18,6 +18,7 @@
 
 
 import android.annotation.UnsupportedAppUsage;
+import android.telephony.cdma.CdmaSmsCbProgramData;
 
 public final class SmsEnvelope {
     /**
@@ -55,12 +56,18 @@
     //...
 
     // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1
-    public static final int SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT  = 0x1000;
-    public static final int SERVICE_CATEGORY_CMAS_EXTREME_THREAT            = 0x1001;
-    public static final int SERVICE_CATEGORY_CMAS_SEVERE_THREAT             = 0x1002;
-    public static final int SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003;
-    public static final int SERVICE_CATEGORY_CMAS_TEST_MESSAGE              = 0x1004;
-    public static final int SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE       = 0x10ff;
+    public static final int SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT  =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT;
+    public static final int SERVICE_CATEGORY_CMAS_EXTREME_THREAT            =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT;
+    public static final int SERVICE_CATEGORY_CMAS_SEVERE_THREAT             =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_SEVERE_THREAT;
+    public static final int SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY;
+    public static final int SERVICE_CATEGORY_CMAS_TEST_MESSAGE              =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_TEST_MESSAGE;
+    public static final int SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE       =
+            CdmaSmsCbProgramData.CATEGORY_CMAS_LAST_RESERVED_VALUE;
 
     /**
      * Provides the type of a SMS message like point to point, broadcast or acknowledge
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 730b210..fe1d9d2 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -92,5 +92,18 @@
         }
         assertTrue("Did not see framework.jar in " + res, sawFramework);
         assertTrue("Did not see services.jar in " + res, sawServices);
+
+
+        // Test the profile contents contain common methods for core-oj that would normally be AOT
+        // compiled.
+        res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file="
+                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar");
+        boolean sawObjectInit = false;
+        for (String line : res.split("\n")) {
+            if (line.contains("Ljava/lang/Object;-><init>()V")) {
+                sawObjectInit = true;
+            }
+        }
+        assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
     }
 }
diff --git a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
index f0c5baa..66c7d06 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
@@ -342,14 +342,14 @@
 
 
 
-    // Code below generated by codegen v1.0.1.
+    // Code below generated by codegen v1.0.3.
     //
     // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java
-    //
-    // CHECKSTYLE:OFF Generated code
+
 
     @IntDef(prefix = "STATE_", value = {
         STATE_UNDEFINED,
@@ -1798,8 +1798,8 @@
     }
 
     @DataClass.Generated(
-            time = 1568235365376L,
-            codegenVersion = "1.0.1",
+            time = 1569956013899L,
+            codegenVersion = "1.0.3",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleDataClass.java",
             inputSignatures = "public static final  java.lang.String STATE_NAME_UNDEFINED\npublic static final  java.lang.String STATE_NAME_ON\npublic static final  java.lang.String STATE_NAME_OFF\npublic static final  int STATE_UNDEFINED\npublic static final  int STATE_ON\npublic static final  int STATE_OFF\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @com.android.codegentest.SampleDataClass.RequestFlags int FLAG_AUGMENTED_REQUEST\nprivate  int mNum\nprivate  int mNum2\nprivate  int mNum4\nprivate @android.annotation.Nullable java.lang.String mName\nprivate @android.annotation.NonNull java.lang.String mName2\nprivate @android.annotation.NonNull java.lang.String mName4\nprivate @android.annotation.Nullable android.view.accessibility.AccessibilityNodeInfo mOtherParcelable\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.codegentest.MyDateParcelling.class) @android.annotation.NonNull java.util.Date mDate\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.NonNull java.util.regex.Pattern mPattern\nprivate @android.annotation.NonNull java.util.List<android.net.LinkAddress> mLinkAddresses2\nprivate @com.android.internal.util.DataClass.PluralOf(\"linkAddress\") @android.annotation.NonNull java.util.ArrayList<android.net.LinkAddress> mLinkAddresses\nprivate @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses4\nprivate @com.android.codegentest.SampleDataClass.StateName @android.annotation.NonNull java.lang.String mStateName\nprivate @com.android.codegentest.SampleDataClass.RequestFlags int mFlags\nprivate @com.android.codegentest.SampleDataClass.State int mState\npublic @android.annotation.NonNull java.lang.CharSequence charSeq\nprivate final @android.annotation.Nullable android.net.LinkAddress[] mLinkAddresses5\nprivate transient  android.net.LinkAddress[] mLinkAddresses6\ntransient  int[] mTmpStorage\nprivate @android.annotation.StringRes int mStringRes\nprivate @android.annotation.IntRange(from=0L, to=6L) int mDayOfWeek\nprivate @android.annotation.Size(2L) @android.annotation.NonNull @com.android.internal.util.DataClass.Each @android.annotation.FloatRange(from=0.0) float[] mCoords\nprivate static  java.lang.String defaultName4()\nprivate  int[] lazyInitTmpStorage()\npublic  android.net.LinkAddress[] getLinkAddresses4()\nprivate  boolean patternEquals(java.util.regex.Pattern)\nprivate  int patternHashCode()\nprivate  void onConstructed()\npublic  void dump(java.io.PrintWriter)\nclass SampleDataClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=true, genEqualsHashCode=true, genToString=true, genForEachField=true, genSetters=true)")
     @Deprecated
diff --git a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
index 86f37fe10..c6bc8de 100644
--- a/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
+++ b/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
@@ -74,14 +74,14 @@
 
 
 
-    // Code below generated by codegen v1.0.1.
+    // Code below generated by codegen v1.0.3.
     //
     // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java
-    //
-    // CHECKSTYLE:OFF Generated code
+
 
     @DataClass.Generated.Member
     /* package-private */ SampleWithCustomBuilder(
@@ -176,8 +176,8 @@
     }
 
     @DataClass.Generated(
-            time = 1568235366386L,
-            codegenVersion = "1.0.1",
+            time = 1569956014908L,
+            codegenVersion = "1.0.3",
             sourceFile = "frameworks/base/tests/Codegen/src/com/android/codegentest/SampleWithCustomBuilder.java",
             inputSignatures = "  long delayAmount\n @android.annotation.NonNull java.util.concurrent.TimeUnit delayUnit\n  long creationTimestamp\nclass SampleWithCustomBuilder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true)\nabstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayAmount(long)\npublic abstract  com.android.codegentest.SampleWithCustomBuilder.Builder setDelayUnit(java.util.concurrent.TimeUnit)\npublic  com.android.codegentest.SampleWithCustomBuilder.Builder setDelay(long,java.util.concurrent.TimeUnit)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
new file mode 100644
index 0000000..022f798
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToAppTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker;
+
+import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
+ */
+@LargeTest
+@RunWith(Parameterized.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CloseImeAutoOpenWindowToAppTest extends CloseImeWindowToAppTest {
+
+    public CloseImeAutoOpenWindowToAppTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
+        mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @Before
+    public void runTransition() {
+        run(editTextLoseFocusToApp((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
+                .includeJankyRuns().build());
+    }
+
+    @FlakyTest(bugId = 141458352)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_imeLayerBecomesInvisible() {
+        super.checkVisibility_imeLayerBecomesInvisible();
+    }
+
+    @FlakyTest(bugId = 141458352)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_imeAppLayerIsAlwaysVisible() {
+        super.checkVisibility_imeAppLayerIsAlwaysVisible();
+    }
+
+    @FlakyTest(bugId = 141458352)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_imeAppWindowIsAlwaysVisible() {
+        super.checkVisibility_imeAppWindowIsAlwaysVisible();
+    }
+
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
new file mode 100644
index 0000000..d6f994b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeAutoOpenWindowToHomeTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.wm.flicker;
+
+import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.LargeTest;
+
+import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper;
+
+import org.junit.Before;
+import org.junit.FixMethodOrder;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+
+/**
+ * Test IME window closing back to app window transitions.
+ * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
+ */
+@LargeTest
+@RunWith(Parameterized.class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CloseImeAutoOpenWindowToHomeTest extends CloseImeWindowToHomeTest {
+
+    public CloseImeAutoOpenWindowToHomeTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
+        mTestApp = new ImeAppAutoFocusHelper(InstrumentationRegistry.getInstrumentation());
+    }
+
+    @Before
+    public void runTransition() {
+        run(editTextLoseFocusToHome((ImeAppAutoFocusHelper) mTestApp, mUiDevice, mBeginRotation)
+                .includeJankyRuns().build());
+    }
+
+    @FlakyTest(bugId = 141458352)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_imeWindowBecomesInvisible() {
+        super.checkVisibility_imeWindowBecomesInvisible();
+    }
+
+    @FlakyTest(bugId = 141458352)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_imeLayerBecomesInvisible() {
+        super.checkVisibility_imeLayerBecomesInvisible();
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
index 9deb977..28da3af 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToAppTest.java
@@ -17,37 +17,39 @@
 package com.android.server.wm.flicker;
 
 import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToApp;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import android.platform.helpers.IAppHelper;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test IME window closing back to app window transitions.
  * To run this test: {@code atest FlickerTests:CloseImeWindowToAppTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToAppTest extends FlickerTestBase {
+public class CloseImeWindowToAppTest extends NonRotationTestBase {
 
-    private static final String IME_WINDOW_TITLE = "InputMethod";
-    private IAppHelper mImeTestApp = new StandardAppHelper(
-            InstrumentationRegistry.getInstrumentation(),
-            "com.android.server.wm.flicker.testapp", "ImeApp");
+    static final String IME_WINDOW_TITLE = "InputMethod";
+
+    public CloseImeWindowToAppTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
+        mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+    }
 
     @Before
     public void runTransition() {
-        super.runTransition(editTextLoseFocusToApp(mUiDevice)
+        run(editTextLoseFocusToApp((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
                 .includeJankyRuns().build());
     }
 
@@ -63,20 +65,14 @@
     @Test
     public void checkVisibility_imeAppLayerIsAlwaysVisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(mImeTestApp.getPackage())
+                .showsLayer(mTestApp.getPackage())
                 .forAllEntries());
     }
 
     @Test
     public void checkVisibility_imeAppWindowIsAlwaysVisible() {
         checkResults(result -> WmTraceSubject.assertThat(result)
-                .showsAppWindowOnTop(mImeTestApp.getPackage())
+                .showsAppWindowOnTop(mTestApp.getPackage())
                 .forAllEntries());
     }
-
-    @Test
-    public void checkCoveredRegion_noUncoveredRegions() {
-        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
-                getDisplayBounds()).forAllEntries());
-    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
index cce5a2a..fc6719e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CloseImeWindowToHomeTest.java
@@ -17,37 +17,39 @@
 package com.android.server.wm.flicker;
 
 import static com.android.server.wm.flicker.CommonTransitions.editTextLoseFocusToHome;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
-
-import android.platform.helpers.IAppHelper;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test IME window closing to home transitions.
  * To run this test: {@code atest FlickerTests:CloseImeWindowToHomeTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class CloseImeWindowToHomeTest extends FlickerTestBase {
+public class CloseImeWindowToHomeTest extends NonRotationTestBase {
 
-    private static final String IME_WINDOW_TITLE = "InputMethod";
-    private IAppHelper mImeTestApp = new StandardAppHelper(
-            InstrumentationRegistry.getInstrumentation(),
-            "com.android.server.wm.flicker.testapp", "ImeApp");
+    static final String IME_WINDOW_TITLE = "InputMethod";
+
+    public CloseImeWindowToHomeTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
+        mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+    }
 
     @Before
     public void runTransition() {
-        super.runTransition(editTextLoseFocusToHome(mUiDevice)
+        run(editTextLoseFocusToHome((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
                 .includeJankyRuns().build());
     }
 
@@ -72,24 +74,18 @@
     @Test
     public void checkVisibility_imeAppLayerBecomesInvisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(mImeTestApp.getPackage())
+                .showsLayer(mTestApp.getPackage())
                 .then()
-                .hidesLayer(mImeTestApp.getPackage())
+                .hidesLayer(mTestApp.getPackage())
                 .forAllEntries());
     }
 
     @Test
     public void checkVisibility_imeAppWindowBecomesInvisible() {
         checkResults(result -> WmTraceSubject.assertThat(result)
-                .showsAppWindowOnTop(mImeTestApp.getPackage())
+                .showsAppWindowOnTop(mTestApp.getPackage())
                 .then()
-                .hidesAppWindowOnTop(mImeTestApp.getPackage())
+                .hidesAppWindowOnTop(mTestApp.getPackage())
                 .forAllEntries());
     }
-
-    @Test
-    public void checkCoveredRegion_noUncoveredRegions() {
-        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
-                getDisplayBounds()).forAllEntries());
-    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
index 1d44ea4..fd31aa5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
@@ -37,10 +37,10 @@
 import android.util.Rational;
 import android.view.Surface;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder;
 import com.android.server.wm.flicker.helpers.AutomationUtils;
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
+import com.android.server.wm.flicker.helpers.PipAppHelper;
 
 /**
  * Collection of common transitions which can be used to test different apps or scenarios.
@@ -73,26 +73,17 @@
         }
     }
 
-    private static void clickEditTextWidget(UiDevice device, IAppHelper testApp) {
-        UiObject2 editText = device.findObject(By.res(testApp.getPackage(), "plain_text_input"));
-        editText.click();
-        sleep(500);
-    }
-
-    private static void clickEnterPipButton(UiDevice device, IAppHelper testApp) {
-        UiObject2 enterPipButton = device.findObject(By.res(testApp.getPackage(), "enter_pip"));
-        enterPipButton.click();
-        sleep(500);
-    }
-
     static TransitionBuilder openAppWarm(IAppHelper testApp, UiDevice
-            device) {
+            device, int beginRotation) {
         return TransitionRunner.newBuilder()
-                .withTag("OpenAppWarm_" + testApp.getLauncherName())
+                .withTag("OpenAppWarm_" + testApp.getLauncherName()
+                        + rotationToString(beginRotation))
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
+                .runBeforeAll(() -> setRotation(device, beginRotation))
                 .runBeforeAll(testApp::open)
                 .runBefore(device::pressHome)
                 .runBefore(device::waitForIdle)
+                .runBefore(() -> setRotation(device, beginRotation))
                 .run(testApp::open)
                 .runAfterAll(testApp::exit)
                 .runAfterAll(AutomationUtils::setDefaultWait)
@@ -127,16 +118,19 @@
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder getOpenAppCold(IAppHelper testApp,
-            UiDevice device) {
+    static TransitionBuilder openAppCold(IAppHelper testApp,
+            UiDevice device, int beginRotation) {
         return TransitionRunner.newBuilder()
-                .withTag("OpenAppCold_" + testApp.getLauncherName())
+                .withTag("OpenAppCold_" + testApp.getLauncherName()
+                        + rotationToString(beginRotation))
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
+                .runBeforeAll(() -> setRotation(device, beginRotation))
                 .runBefore(testApp::exit)
                 .runBefore(device::waitForIdle)
                 .run(testApp::open)
                 .runAfterAll(testApp::exit)
+                .runAfterAll(() -> setRotation(device, Surface.ROTATION_0))
                 .repeat(ITERATIONS);
     }
 
@@ -201,28 +195,31 @@
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder editTextSetFocus(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "ImeApp");
+    static TransitionBuilder editTextSetFocus(ImeAppHelper testApp, UiDevice device,
+            int beginRotation) {
         return TransitionRunner.newBuilder()
-                .withTag("editTextSetFocus_" + testApp.getLauncherName())
+                .withTag("editTextSetFocus_" + testApp.getLauncherName()
+                        + rotationToString(beginRotation))
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
+                .runBefore(() -> setRotation(device, beginRotation))
                 .runBefore(testApp::open)
-                .run(() -> clickEditTextWidget(device, testApp))
+                .run(() -> testApp.clickEditTextWidget(device))
                 .runAfterAll(testApp::exit)
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, IAppHelper testAppBottom,
-            UiDevice device, Rational startRatio, Rational stopRatio) {
+    static TransitionBuilder resizeSplitScreen(IAppHelper testAppTop, ImeAppHelper testAppBottom,
+            UiDevice device, int beginRotation, Rational startRatio, Rational stopRatio) {
         String testTag = "resizeSplitScreen_" + testAppTop.getLauncherName() + "_"
                 + testAppBottom.getLauncherName() + "_"
                 + startRatio.toString().replace("/", ":") + "_to_"
-                + stopRatio.toString().replace("/", ":");
+                + stopRatio.toString().replace("/", ":") + "_"
+                + rotationToString(beginRotation);
         return TransitionRunner.newBuilder()
                 .withTag(testTag)
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
+                .runBeforeAll(() -> setRotation(device, beginRotation))
                 .runBeforeAll(() -> clearRecents(device))
                 .runBefore(testAppBottom::open)
                 .runBefore(device::pressHome)
@@ -234,6 +231,7 @@
                             By.res(device.getLauncherPackageName(), "snapshot"));
                     snapshot.click();
                 })
+                .runBefore(() -> testAppBottom.clickEditTextWidget(device))
                 .runBefore(() -> AutomationUtils.resizeSplitScreen(device, startRatio))
                 .run(() -> AutomationUtils.resizeSplitScreen(device, stopRatio))
                 .runAfter(() -> exitSplitScreen(device))
@@ -243,74 +241,70 @@
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder editTextLoseFocusToHome(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "ImeApp");
+    static TransitionBuilder editTextLoseFocusToHome(ImeAppHelper testApp, UiDevice device,
+            int beginRotation) {
         return TransitionRunner.newBuilder()
-                .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName())
+                .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()
+                        + rotationToString(beginRotation))
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
+                .runBefore(() -> setRotation(device, beginRotation))
                 .runBefore(testApp::open)
-                .runBefore(() -> clickEditTextWidget(device, testApp))
+                .runBefore(() -> testApp.clickEditTextWidget(device))
                 .run(device::pressHome)
                 .run(device::waitForIdle)
                 .runAfterAll(testApp::exit)
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder editTextLoseFocusToApp(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "ImeApp");
+    static TransitionBuilder editTextLoseFocusToApp(ImeAppHelper testApp, UiDevice device,
+            int beginRotation) {
         return TransitionRunner.newBuilder()
-                .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName())
+                .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()
+                        + rotationToString(beginRotation))
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
+                .runBefore(() -> setRotation(device, beginRotation))
                 .runBefore(testApp::open)
-                .runBefore(() -> clickEditTextWidget(device, testApp))
+                .runBefore(() -> testApp.clickEditTextWidget(device))
                 .run(device::pressBack)
                 .run(device::waitForIdle)
                 .runAfterAll(testApp::exit)
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder enterPipMode(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "PipApp");
+    static TransitionBuilder enterPipMode(PipAppHelper testApp, UiDevice device) {
         return TransitionRunner.newBuilder()
                 .withTag("enterPipMode_" + testApp.getLauncherName())
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(testApp::open)
-                .run(() -> clickEnterPipButton(device, testApp))
+                .run(() -> testApp.clickEnterPipButton(device))
                 .runAfter(() -> closePipWindow(device))
                 .runAfterAll(testApp::exit)
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder exitPipModeToHome(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "PipApp");
+    static TransitionBuilder exitPipModeToHome(PipAppHelper testApp, UiDevice device) {
         return TransitionRunner.newBuilder()
                 .withTag("exitPipModeToHome_" + testApp.getLauncherName())
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(testApp::open)
-                .runBefore(() -> clickEnterPipButton(device, testApp))
+                .runBefore(() -> testApp.clickEnterPipButton(device))
                 .run(() -> closePipWindow(device))
                 .run(device::waitForIdle)
                 .runAfterAll(testApp::exit)
                 .repeat(ITERATIONS);
     }
 
-    static TransitionBuilder exitPipModeToApp(UiDevice device) {
-        IAppHelper testApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "PipApp");
+    static TransitionBuilder exitPipModeToApp(PipAppHelper testApp, UiDevice device) {
         return TransitionRunner.newBuilder()
                 .withTag("exitPipModeToApp_" + testApp.getLauncherName())
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(testApp::open)
-                .runBefore(() -> clickEnterPipButton(device, testApp))
+                .runBefore(() -> testApp.clickEnterPipButton(device))
                 .run(() -> expandPipWindow(device))
                 .run(device::waitForIdle)
                 .runAfterAll(testApp::exit)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
index 9836655..8f0177c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.java
@@ -25,6 +25,9 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
+import com.android.server.wm.flicker.helpers.PipAppHelper;
+
 import org.junit.FixMethodOrder;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -44,23 +47,25 @@
     private UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
 
     /**
-     * atest FlickerTest:DebugTests#openAppCold
+     * atest FlickerTests:DebugTest#openAppCold
      */
     @Test
     public void openAppCold() {
-        CommonTransitions.getOpenAppCold(testApp, uiDevice).recordAllRuns().build().run();
+        CommonTransitions.openAppCold(testApp, uiDevice, Surface.ROTATION_0)
+                .recordAllRuns().build().run();
     }
 
     /**
-     * atest FlickerTest:DebugTests#openAppWarm
+     * atest FlickerTests:DebugTest#openAppWarm
      */
     @Test
     public void openAppWarm() {
-        CommonTransitions.openAppWarm(testApp, uiDevice).recordAllRuns().build().run();
+        CommonTransitions.openAppWarm(testApp, uiDevice, Surface.ROTATION_0)
+                .recordAllRuns().build().run();
     }
 
     /**
-     * atest FlickerTest:DebugTests#changeOrientationFromNaturalToLeft
+     * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
      */
     @Test
     public void changeOrientationFromNaturalToLeft() {
@@ -69,7 +74,7 @@
     }
 
     /**
-     * atest FlickerTest:DebugTests#closeAppWithBackKey
+     * atest FlickerTests:DebugTest#closeAppWithBackKey
      */
     @Test
     public void closeAppWithBackKey() {
@@ -77,7 +82,7 @@
     }
 
     /**
-     * atest FlickerTest:DebugTests#closeAppWithHomeKey
+     * atest FlickerTests:DebugTest#closeAppWithHomeKey
      */
     @Test
     public void closeAppWithHomeKey() {
@@ -85,7 +90,7 @@
     }
 
     /**
-     * atest FlickerTest:DebugTests#openAppToSplitScreen
+     * atest FlickerTests:DebugTest#openAppToSplitScreen
      */
     @Test
     public void openAppToSplitScreen() {
@@ -94,7 +99,7 @@
     }
 
     /**
-     * atest FlickerTest:DebugTests#splitScreenToLauncher
+     * atest FlickerTests:DebugTest#splitScreenToLauncher
      */
     @Test
     public void splitScreenToLauncher() {
@@ -104,70 +109,80 @@
     }
 
     /**
-     * atest FlickerTest:DebugTests#resizeSplitScreen
+     * atest FlickerTests:DebugTest#resizeSplitScreen
      */
     @Test
     public void resizeSplitScreen() {
-        IAppHelper bottomApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "ImeApp");
-        CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, new Rational(1, 3),
-                new Rational(2, 3)).includeJankyRuns().recordEachRun().build().run();
+        ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.resizeSplitScreen(testApp, bottomApp, uiDevice, Surface.ROTATION_0,
+                new Rational(1, 3), new Rational(2, 3))
+                .includeJankyRuns().recordEachRun().build().run();
     }
 
     // IME tests
 
     /**
-     * atest FlickerTest:DebugTests#editTextSetFocus
+     * atest FlickerTests:DebugTest#editTextSetFocus
      */
     @Test
     public void editTextSetFocus() {
-        CommonTransitions.editTextSetFocus(uiDevice).includeJankyRuns().recordEachRun()
+        ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.editTextSetFocus(testApp, uiDevice, Surface.ROTATION_0)
+                .includeJankyRuns().recordEachRun()
                 .build().run();
     }
 
     /**
-     * atest FlickerTest:DebugTests#editTextLoseFocusToHome
+     * atest FlickerTests:DebugTest#editTextLoseFocusToHome
      */
     @Test
     public void editTextLoseFocusToHome() {
-        CommonTransitions.editTextLoseFocusToHome(uiDevice).includeJankyRuns().recordEachRun()
+        ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
+                .includeJankyRuns().recordEachRun()
                 .build().run();
     }
 
     /**
-     * atest FlickerTest:DebugTests#editTextLoseFocusToApp
+     * atest FlickerTests:DebugTest#editTextLoseFocusToApp
      */
     @Test
     public void editTextLoseFocusToApp() {
-        CommonTransitions.editTextLoseFocusToHome(uiDevice).includeJankyRuns().recordEachRun()
+        ImeAppHelper testApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.editTextLoseFocusToHome(testApp, uiDevice, Surface.ROTATION_0)
+                .includeJankyRuns().recordEachRun()
                 .build().run();
     }
 
     // PIP tests
 
     /**
-     * atest FlickerTest:DebugTests#enterPipMode
+     * atest FlickerTests:DebugTest#enterPipMode
      */
     @Test
     public void enterPipMode() {
-        CommonTransitions.enterPipMode(uiDevice).includeJankyRuns().recordEachRun().build().run();
-    }
-
-    /**
-     * atest FlickerTest:DebugTests#exitPipModeToHome
-     */
-    @Test
-    public void exitPipModeToHome() {
-        CommonTransitions.exitPipModeToHome(uiDevice).includeJankyRuns().recordEachRun()
+        PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.enterPipMode(testApp, uiDevice).includeJankyRuns().recordEachRun()
                 .build().run();
     }
 
     /**
-     * atest FlickerTest:DebugTests#exitPipModeToApp
+     * atest FlickerTests:DebugTest#exitPipModeToHome
+     */
+    @Test
+    public void exitPipModeToHome() {
+        PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.exitPipModeToHome(testApp, uiDevice).includeJankyRuns().recordEachRun()
+                .build().run();
+    }
+
+    /**
+     * atest FlickerTests:DebugTest#exitPipModeToApp
      */
     @Test
     public void exitPipModeToApp() {
-        CommonTransitions.exitPipModeToApp(uiDevice).includeJankyRuns().recordEachRun()
+        PipAppHelper testApp = new PipAppHelper(InstrumentationRegistry.getInstrumentation());
+        CommonTransitions.exitPipModeToApp(testApp, uiDevice).includeJankyRuns().recordEachRun()
                 .build().run();
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
index 6e8e0c3..883d59e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
@@ -98,7 +98,7 @@
     /**
      * Runs a transition, returns a cached result if the transition has run before.
      */
-    void runTransition(TransitionRunner transition) {
+    void run(TransitionRunner transition) {
         if (transitionResults.containsKey(transition.getTestTag())) {
             mResults = transitionResults.get(transition.getTestTag());
             return;
@@ -111,6 +111,13 @@
     }
 
     /**
+     * Runs a transition, returns a cached result if the transition has run before.
+     */
+    void runTransition(TransitionRunner transition) {
+        run(transition);
+    }
+
+    /**
      * Goes through a list of transition results and checks assertions on each result.
      */
     void checkResults(Consumer<TransitionResult> assertion) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
new file mode 100644
index 0000000..54941dc
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.java
@@ -0,0 +1,80 @@
+/*
+ * 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.wm.flicker;
+
+import static android.view.Surface.rotationToString;
+
+import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
+
+import android.graphics.Rect;
+import android.view.Surface;
+
+import androidx.test.filters.FlakyTest;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public abstract class NonRotationTestBase extends FlickerTestBase {
+
+    int mBeginRotation;
+
+    public NonRotationTestBase(String beginRotationName, int beginRotation) {
+        this.mBeginRotation = beginRotation;
+    }
+
+    @Parameters(name = "{0}")
+    public static Collection<Object[]> getParams() {
+        int[] supportedRotations =
+                {Surface.ROTATION_0, Surface.ROTATION_90};
+        Collection<Object[]> params = new ArrayList<>();
+
+        for (int begin : supportedRotations) {
+            params.add(new Object[]{rotationToString(begin), begin});
+        }
+
+        return params;
+    }
+
+    @FlakyTest(bugId = 141361128)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkCoveredRegion_noUncoveredRegions() {
+        Rect displayBounds = getDisplayBounds(mBeginRotation);
+        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
+                displayBounds).forAllEntries());
+    }
+
+    @FlakyTest(bugId = 141361128)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_navBarLayerIsAlwaysVisible() {
+        checkResults(result -> LayersTraceSubject.assertThat(result)
+                .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
+    }
+
+    @FlakyTest(bugId = 141361128)
+    @Ignore("Waiting bug feedback")
+    @Test
+    public void checkVisibility_statusBarLayerIsAlwaysVisible() {
+        checkResults(result -> LayersTraceSubject.assertThat(result)
+                .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
index 8d99054..efdfaee 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppColdTest.java
@@ -16,14 +16,12 @@
 
 package com.android.server.wm.flicker;
 
-import static com.android.server.wm.flicker.CommonTransitions.getOpenAppCold;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
+import static com.android.server.wm.flicker.CommonTransitions.openAppCold;
 import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
@@ -31,36 +29,28 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test cold launch app from launcher.
  * To run this test: {@code atest FlickerTests:OpenAppColdTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppColdTest extends FlickerTestBase {
+public class OpenAppColdTest extends NonRotationTestBase {
 
-    public OpenAppColdTest() {
+    public OpenAppColdTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
         this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
                 "com.android.server.wm.flicker.testapp", "SimpleApp");
     }
 
     @Before
     public void runTransition() {
-        super.runTransition(getOpenAppCold(mTestApp, mUiDevice).build());
-    }
-
-    @Test
-    public void checkVisibility_navBarWindowIsAlwaysVisible() {
-        checkResults(result -> assertThat(result)
-                .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_statusBarWindowIsAlwaysVisible() {
-        checkResults(result -> assertThat(result)
-                .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
+        run(openAppCold(mTestApp, mUiDevice, mBeginRotation)
+                .includeJankyRuns().build());
     }
 
     @Test
@@ -72,6 +62,8 @@
                 .forAllEntries());
     }
 
+    @FlakyTest(bugId = 140855415)
+    @Ignore("Waiting bug feedback")
     @Test
     public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
         checkResults(result -> assertThat(result)
@@ -83,26 +75,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 141235985)
-    @Ignore("Waiting bug feedback")
-    public void checkCoveredRegion_noUncoveredRegions() {
-        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
-                getDisplayBounds()).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_navBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_statusBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
-    @Test
     public void checkVisibility_wallpaperLayerBecomesInvisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
                 .showsLayer("Wallpaper")
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
index e8702c2..7ce6315 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenAppWarmTest.java
@@ -17,13 +17,11 @@
 package com.android.server.wm.flicker;
 
 import static com.android.server.wm.flicker.CommonTransitions.openAppWarm;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
 import static com.android.server.wm.flicker.WmTraceSubject.assertThat;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
@@ -31,36 +29,28 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test warm launch app.
  * To run this test: {@code atest FlickerTests:OpenAppWarmTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenAppWarmTest extends FlickerTestBase {
+public class OpenAppWarmTest extends NonRotationTestBase {
 
-    public OpenAppWarmTest() {
+    public OpenAppWarmTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
         this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
                 "com.android.server.wm.flicker.testapp", "SimpleApp");
     }
 
     @Before
     public void runTransition() {
-        super.runTransition(openAppWarm(mTestApp, mUiDevice).includeJankyRuns().build());
-    }
-
-    @Test
-    public void checkVisibility_navBarIsAlwaysVisible() {
-        checkResults(result -> assertThat(result)
-                .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_statusBarIsAlwaysVisible() {
-        checkResults(result -> assertThat(result)
-                .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries());
+        super.runTransition(openAppWarm(mTestApp, mUiDevice, mBeginRotation)
+                .includeJankyRuns().build());
     }
 
     @Test
@@ -72,6 +62,8 @@
                 .forAllEntries());
     }
 
+    @FlakyTest(bugId = 140855415)
+    @Ignore("Waiting bug feedback")
     @Test
     public void checkZOrder_appWindowReplacesLauncherAsTopWindow() {
         checkResults(result -> assertThat(result)
@@ -82,26 +74,6 @@
                 .forAllEntries());
     }
 
-    @FlakyTest(bugId = 141235985)
-    @Ignore("Waiting bug feedback")
-    @Test
-    public void checkCoveredRegion_noUncoveredRegions() {
-        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
-                getDisplayBounds()).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_navBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_statusBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries());
-    }
-
     @Test
     public void checkVisibility_wallpaperLayerBecomesInvisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
index 9f5cfce..91d4a05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/OpenImeWindowTest.java
@@ -17,31 +17,39 @@
 package com.android.server.wm.flicker;
 
 import static com.android.server.wm.flicker.CommonTransitions.editTextSetFocus;
-import static com.android.server.wm.flicker.WindowUtils.getDisplayBounds;
 
+import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test IME window opening transitions.
  * To run this test: {@code atest FlickerTests:OpenImeWindowTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class OpenImeWindowTest extends FlickerTestBase {
+public class OpenImeWindowTest extends NonRotationTestBase {
 
     private static final String IME_WINDOW_TITLE = "InputMethod";
 
+    public OpenImeWindowTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
+        mTestApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+    }
+
     @Before
     public void runTransition() {
-        super.runTransition(editTextSetFocus(mUiDevice)
+        run(editTextSetFocus((ImeAppHelper) mTestApp, mUiDevice, mBeginRotation)
                 .includeJankyRuns().build());
     }
 
@@ -62,10 +70,4 @@
                 .showsLayer(IME_WINDOW_TITLE)
                 .forAllEntries());
     }
-
-    @Test
-    public void checkCoveredRegion_noUncoveredRegions() {
-        checkResults(result -> LayersTraceSubject.assertThat(result).coversRegion(
-                getDisplayBounds()).forAllEntries());
-    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
index 1031baf..29b6240 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ResizeSplitScreenTest.java
@@ -24,13 +24,13 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.graphics.Rect;
-import android.platform.helpers.IAppHelper;
 import android.util.Rational;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.wm.flicker.helpers.ImeAppHelper;
 
 import org.junit.Before;
 import org.junit.FixMethodOrder;
@@ -38,57 +38,48 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
 
 /**
  * Test split screen resizing window transitions.
  * To run this test: {@code atest FlickerTests:ResizeSplitScreenTest}
  */
 @LargeTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(Parameterized.class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@FlakyTest(bugId = 140856143)
+@FlakyTest(bugId = 140854698)
 @Ignore("Waiting bug feedback")
-public class ResizeSplitScreenTest extends FlickerTestBase {
+public class ResizeSplitScreenTest extends NonRotationTestBase {
 
-    public ResizeSplitScreenTest() {
+    private static String sSimpleActivity = "SimpleActivity";
+    private static String sImeActivity = "ImeActivity";
+
+    public ResizeSplitScreenTest(String beginRotationName, int beginRotation) {
+        super(beginRotationName, beginRotation);
+
         this.mTestApp = new StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
                 "com.android.server.wm.flicker.testapp", "SimpleApp");
     }
 
     @Before
     public void runTransition() {
-        IAppHelper bottomApp = new StandardAppHelper(InstrumentationRegistry
-                .getInstrumentation(),
-                "com.android.server.wm.flicker.testapp", "ImeApp");
-        super.runTransition(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, new Rational(1, 3),
-                new Rational(2, 3)).includeJankyRuns().build());
-    }
-
-    @Test
-    public void checkVisibility_navBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(NAVIGATION_BAR_WINDOW_TITLE)
-                .forAllEntries());
-    }
-
-    @Test
-    public void checkVisibility_statusBarLayerIsAlwaysVisible() {
-        checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer(STATUS_BAR_WINDOW_TITLE)
-                .forAllEntries());
+        ImeAppHelper bottomApp = new ImeAppHelper(InstrumentationRegistry.getInstrumentation());
+        run(resizeSplitScreen(mTestApp, bottomApp, mUiDevice, mBeginRotation,
+                new Rational(1, 3), new Rational(2, 3))
+                .includeJankyRuns().build());
     }
 
     @Test
     public void checkVisibility_topAppLayerIsAlwaysVisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer("SimpleActivity")
+                .showsLayer(sSimpleActivity)
                 .forAllEntries());
     }
 
     @Test
     public void checkVisibility_bottomAppLayerIsAlwaysVisible() {
         checkResults(result -> LayersTraceSubject.assertThat(result)
-                .showsLayer("ImeActivity")
+                .showsLayer(sImeActivity)
                 .forAllEntries());
     }
 
@@ -149,11 +140,11 @@
                     displayBounds.bottom - getNavigationBarHeight());
 
             LayersTraceSubject.assertThat(result)
-                    .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
+                    .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
                     .atTheEnd();
 
             LayersTraceSubject.assertThat(result)
-                    .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
+                    .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
                     .atTheEnd();
         });
     }
@@ -175,14 +166,14 @@
     @Test
     public void checkVisibility_topAppWindowIsAlwaysVisible() {
         checkResults(result -> WmTraceSubject.assertThat(result)
-                .showsAppWindow("SimpleActivity")
+                .showsAppWindow(sSimpleActivity)
                 .forAllEntries());
     }
 
     @Test
     public void checkVisibility_bottomAppWindowIsAlwaysVisible() {
         checkResults(result -> WmTraceSubject.assertThat(result)
-                .showsAppWindow("ImeActivity")
+                .showsAppWindow(sImeActivity)
                 .forAllEntries());
     }
 
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
new file mode 100644
index 0000000..42977f5
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers;
+
+import android.app.Instrumentation;
+
+import com.android.server.wm.flicker.StandardAppHelper;
+
+public abstract class FlickerAppHelper extends StandardAppHelper {
+
+    static int sFindTimeout = 10000;
+    static String sFlickerPackage = "com.android.server.wm.flicker.testapp";
+
+    public FlickerAppHelper(Instrumentation instr, String launcherName) {
+        super(instr, sFlickerPackage, launcherName);
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
new file mode 100644
index 0000000..56e1118
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers;
+
+import android.app.Instrumentation;
+import android.support.test.uiautomator.UiDevice;
+
+public class ImeAppAutoFocusHelper extends ImeAppHelper {
+
+    public ImeAppAutoFocusHelper(Instrumentation instr) {
+        super(instr, "ImeAppAutoFocus");
+    }
+
+    public void clickEditTextWidget(UiDevice device) {
+        // do nothing (the app is focused automatically)
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
new file mode 100644
index 0000000..098fd6d
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.java
@@ -0,0 +1,41 @@
+/*
+ * 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.wm.flicker.helpers;
+
+import static android.os.SystemClock.sleep;
+
+import android.app.Instrumentation;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+
+public class ImeAppHelper extends FlickerAppHelper {
+
+    ImeAppHelper(Instrumentation instr, String launcherName) {
+        super(instr, launcherName);
+    }
+
+    public ImeAppHelper(Instrumentation instr) {
+        this(instr, "ImeApp");
+    }
+
+    public void clickEditTextWidget(UiDevice device) {
+        UiObject2 editText = device.findObject(By.res(getPackage(), "plain_text_input"));
+        editText.click();
+        sleep(500);
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
new file mode 100644
index 0000000..d00e11b
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.java
@@ -0,0 +1,43 @@
+/*
+ * 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.wm.flicker.helpers;
+
+import static com.android.server.wm.flicker.helpers.AutomationUtils.getPipWindowSelector;
+
+import android.app.Instrumentation;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+public class PipAppHelper extends FlickerAppHelper {
+
+    public PipAppHelper(Instrumentation instr) {
+        super(instr, "PipApp");
+    }
+
+    public void clickEnterPipButton(UiDevice device) {
+        UiObject2 enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"));
+        enterPipButton.click();
+        UiObject2 pipWindow = device.wait(Until.findObject(getPipWindowSelector()), sFindTimeout);
+
+        if (pipWindow == null) {
+            throw new RuntimeException("Unable to find PIP window");
+        }
+    }
+
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index b694172..0fe9682 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -38,6 +38,15 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".ImeActivityAutoFocus"
+                  android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
+                  android:windowSoftInputMode="stateVisible"
+                  android:label="ImeAppAutoFocus">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
         <activity android:name=".PipActivity"
                   android:resizeableActivity="true"
                   android:supportsPictureInPicture="true"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
index d5eb023..4708cfd 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:focusableInTouchMode="true"
     android:background="@android:color/holo_green_light">
     <EditText android:id="@+id/plain_text_input"
               android:layout_height="wrap_content"
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
new file mode 100644
index 0000000..05da717
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivityAutoFocus.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.widget.EditText;
+
+public class ImeActivityAutoFocus extends ImeActivity {
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        EditText editTextField = findViewById(R.id.plain_text_input);
+        editTextField.requestFocus();
+    }
+}
diff --git a/tests/MirrorSurfaceTest/Android.bp b/tests/MirrorSurfaceTest/Android.bp
new file mode 100644
index 0000000..e359c64
--- /dev/null
+++ b/tests/MirrorSurfaceTest/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+    name: "MirrorSurfaceTest",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    certificate: "platform",
+}
diff --git a/tests/MirrorSurfaceTest/AndroidManifest.xml b/tests/MirrorSurfaceTest/AndroidManifest.xml
new file mode 100644
index 0000000..123cd0f
--- /dev/null
+++ b/tests/MirrorSurfaceTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.google.android.test.mirrorsurface">
+    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+
+    <application android:label="MirrorSurfaceTest">
+        <activity android:name=".MirrorSurfaceActivity"
+                  android:label="Mirror Surface"
+                  android:configChanges="orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml b/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml
new file mode 100644
index 0000000..73b509f
--- /dev/null
+++ b/tests/MirrorSurfaceTest/res/layout/activity_mirror_surface.xml
@@ -0,0 +1,111 @@
+<?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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="20dp"
+        android:orientation="horizontal">
+
+        <Button
+            android:id="@+id/mirror_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="20dp"
+            android:text="Mirror"
+            android:textSize="20dp" />
+
+        <Button
+            android:id="@+id/remove_mirror_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="20dp"
+            android:text="Remove Mirror"
+            android:textSize="20dp" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="40dp"
+        android:layout_marginRight="40dp"
+        android:layout_marginTop="10dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="20dp"
+            android:text="SCALE: " />
+
+        <EditText
+            android:hint="0.5"
+            android:id="@+id/scale"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="numberDecimal" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="40dp"
+        android:layout_marginRight="40dp"
+        android:layout_marginTop="10dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="20dp"
+            android:text="DISPLAY FRAME: " />
+
+        <EditText
+            android:hint="0, 0, 20, 20"
+            android:id="@+id/displayFrame"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="numberDecimal|text"/>
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="40dp"
+        android:layout_marginRight="40dp"
+        android:layout_marginTop="10dp"
+        android:orientation="horizontal">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="20dp"
+            android:text="SOURCE POSITION: " />
+
+        <TextView
+            android:id="@+id/sourcePosition"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="numberDecimal|text"/>
+    </LinearLayout>
+</LinearLayout>
diff --git a/tests/MirrorSurfaceTest/res/layout/move_view.xml b/tests/MirrorSurfaceTest/res/layout/move_view.xml
new file mode 100644
index 0000000..5707700
--- /dev/null
+++ b/tests/MirrorSurfaceTest/res/layout/move_view.xml
@@ -0,0 +1,101 @@
+<?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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:layout_margin="20dp"
+             android:gravity="center">
+
+    <RelativeLayout
+        android:id="@+id/arrows"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageButton
+            android:id="@+id/up_arrow"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_toEndOf="@+id/right_arrow"
+            android:background="@android:color/holo_green_light"
+            android:padding="10dp"
+            android:src="@android:drawable/arrow_up_float" />
+
+        <ImageButton
+            android:id="@+id/down_arrow"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/up_arrow"
+            android:layout_marginTop="80dp"
+            android:layout_toEndOf="@+id/right_arrow"
+            android:background="@android:color/holo_green_light"
+            android:padding="10dp"
+            android:src="@android:drawable/arrow_down_float" />
+
+        <ImageButton
+            android:id="@+id/right_arrow"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignTop="@+id/up_arrow"
+            android:layout_alignBottom="@+id/down_arrow"
+            android:layout_marginTop="55dp"
+            android:layout_marginEnd="15dp"
+            android:layout_marginBottom="55dp"
+            android:background="@android:color/holo_green_light"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:rotation="90"
+            android:src="@android:drawable/arrow_down_float" />
+
+        <ImageButton
+            android:id="@+id/left_arrow"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignTop="@+id/up_arrow"
+            android:layout_alignBottom="@+id/down_arrow"
+            android:layout_marginStart="15dp"
+            android:layout_marginTop="55dp"
+            android:layout_marginBottom="55dp"
+            android:layout_toEndOf="@+id/down_arrow"
+            android:background="@android:color/holo_green_light"
+            android:paddingLeft="10dp"
+            android:paddingRight="10dp"
+            android:rotation="-90"
+            android:src="@android:drawable/arrow_down_float" />
+    </RelativeLayout>
+
+    <RelativeLayout
+
+        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <Button
+            android:id="@+id/zoom_in_button"
+            android:layout_width="40dp"
+            android:layout_marginBottom="-8dp"
+            android:layout_height="40dp"
+            android:text="+" />
+
+        <Button
+            android:layout_below="@+id/zoom_in_button"
+            android:id="@+id/zoom_out_button"
+            android:layout_width="40dp"
+            android:layout_height="40dp"
+            android:text="-" />
+    </RelativeLayout>
+</FrameLayout>
\ No newline at end of file
diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
new file mode 100644
index 0000000..b863713
--- /dev/null
+++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
@@ -0,0 +1,441 @@
+/*
+ * 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.google.android.test.mirrorsurface;
+
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.IWindowManager;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class MirrorSurfaceActivity extends Activity implements View.OnClickListener,
+        View.OnLongClickListener, View.OnTouchListener {
+    private static final int BORDER_SIZE = 10;
+    private static final int DEFAULT_SCALE = 2;
+    private static final int DEFAULT_BORDER_COLOR = Color.argb(255, 255, 153, 0);
+    private static final int MOVE_FRAME_AMOUNT = 20;
+
+    private IWindowManager mIWm;
+    private WindowManager mWm;
+
+    private SurfaceControl mSurfaceControl = new SurfaceControl();
+    private SurfaceControl mBorderSc;
+
+    private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+    private View mOverlayView;
+    private View mArrowOverlay;
+
+    private Rect mDisplayBounds = new Rect();
+
+    private EditText mScaleText;
+    private EditText mDisplayFrameText;
+    private TextView mSourcePositionText;
+
+    private Rect mTmpRect = new Rect();
+    private final Surface mTmpSurface = new Surface();
+
+    private boolean mHasMirror;
+
+    private Rect mCurrFrame = new Rect();
+    private float mCurrScale = DEFAULT_SCALE;
+
+    private final Handler mHandler = new Handler();
+
+    private MoveMirrorRunnable mMoveMirrorRunnable = new MoveMirrorRunnable();
+    private boolean mIsPressedDown = false;
+
+    private int mDisplayId;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_mirror_surface);
+        mWm = (WindowManager) getSystemService(WINDOW_SERVICE);
+        mIWm = WindowManagerGlobal.getWindowManagerService();
+
+        DisplayMetrics displayMetrics = new DisplayMetrics();
+        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
+        mDisplayBounds.set(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+
+        mScaleText = findViewById(R.id.scale);
+        mDisplayFrameText = findViewById(R.id.displayFrame);
+        mSourcePositionText = findViewById(R.id.sourcePosition);
+
+        mCurrFrame.set(0, 0, mDisplayBounds.width() / 2, mDisplayBounds.height() / 2);
+        mCurrScale = DEFAULT_SCALE;
+
+        mDisplayId = getWindowManager().getDefaultDisplay().getDisplayId();
+        updateEditTexts();
+
+        findViewById(R.id.mirror_button).setOnClickListener(view -> {
+            if (mArrowOverlay == null) {
+                createArrowOverlay();
+            }
+            createOrUpdateMirror();
+        });
+
+        findViewById(R.id.remove_mirror_button).setOnClickListener(v -> {
+            removeMirror();
+            removeArrowOverlay();
+        });
+
+        createMirrorOverlay();
+    }
+
+    private void updateEditTexts() {
+        mDisplayFrameText.setText(
+                String.format("%s, %s, %s, %s", mCurrFrame.left, mCurrFrame.top, mCurrFrame.right,
+                        mCurrFrame.bottom));
+        mScaleText.setText(String.valueOf(mCurrScale));
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        if (mOverlayView != null) {
+            removeMirror();
+            mWm.removeView(mOverlayView);
+            mOverlayView = null;
+        }
+        removeArrowOverlay();
+    }
+
+    private void createArrowOverlay() {
+        mArrowOverlay = getLayoutInflater().inflate(R.layout.move_view, null);
+        WindowManager.LayoutParams arrowParams = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT,
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.RGBA_8888);
+        arrowParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
+        mWm.addView(mArrowOverlay, arrowParams);
+
+        View leftArrow = mArrowOverlay.findViewById(R.id.left_arrow);
+        View topArrow = mArrowOverlay.findViewById(R.id.up_arrow);
+        View rightArrow = mArrowOverlay.findViewById(R.id.right_arrow);
+        View bottomArrow = mArrowOverlay.findViewById(R.id.down_arrow);
+
+        leftArrow.setOnClickListener(this);
+        topArrow.setOnClickListener(this);
+        rightArrow.setOnClickListener(this);
+        bottomArrow.setOnClickListener(this);
+
+        leftArrow.setOnLongClickListener(this);
+        topArrow.setOnLongClickListener(this);
+        rightArrow.setOnLongClickListener(this);
+        bottomArrow.setOnLongClickListener(this);
+
+        leftArrow.setOnTouchListener(this);
+        topArrow.setOnTouchListener(this);
+        rightArrow.setOnTouchListener(this);
+        bottomArrow.setOnTouchListener(this);
+
+        mArrowOverlay.findViewById(R.id.zoom_in_button).setOnClickListener(v -> {
+            if (mCurrScale <= 1) {
+                mCurrScale *= 2;
+            } else {
+                mCurrScale += 0.5;
+            }
+
+            updateMirror(mCurrFrame, mCurrScale);
+        });
+        mArrowOverlay.findViewById(R.id.zoom_out_button).setOnClickListener(v -> {
+            if (mCurrScale <= 1) {
+                mCurrScale /= 2;
+            } else {
+                mCurrScale -= 0.5;
+            }
+
+            updateMirror(mCurrFrame, mCurrScale);
+        });
+    }
+
+    private void removeArrowOverlay() {
+        if (mArrowOverlay != null) {
+            mWm.removeView(mArrowOverlay);
+            mArrowOverlay = null;
+        }
+    }
+
+    private void createMirrorOverlay() {
+        mOverlayView = new LinearLayout(this);
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(mDisplayBounds.width(),
+                mDisplayBounds.height(),
+                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+                WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.RGBA_8888);
+        params.gravity = Gravity.LEFT | Gravity.TOP;
+        params.setTitle("Mirror Overlay");
+        mOverlayView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+
+        mWm.addView(mOverlayView, params);
+
+    }
+
+    private void removeMirror() {
+        if (mSurfaceControl.isValid()) {
+            mTransaction.remove(mSurfaceControl).apply();
+        }
+        mHasMirror = false;
+    }
+
+    private void createOrUpdateMirror() {
+        if (mHasMirror) {
+            updateMirror(getDisplayFrame(), getScale());
+        } else {
+            createMirror(getDisplayFrame(), getScale());
+        }
+
+    }
+
+    private Rect getDisplayFrame() {
+        mTmpRect.setEmpty();
+        String[] frameVals = mDisplayFrameText.getText().toString().split("\\s*,\\s*");
+        if (frameVals.length != 4) {
+            return mTmpRect;
+        }
+
+        try {
+            mTmpRect.set(Integer.parseInt(frameVals[0]), Integer.parseInt(frameVals[1]),
+                    Integer.parseInt(frameVals[2]), Integer.parseInt(frameVals[3]));
+        } catch (Exception e) {
+            mTmpRect.setEmpty();
+        }
+
+        return mTmpRect;
+    }
+
+    private float getScale() {
+        try {
+            return Float.parseFloat(mScaleText.getText().toString());
+        } catch (Exception e) {
+            return -1;
+        }
+    }
+
+    private void createMirror(Rect displayFrame, float scale) {
+        boolean success = false;
+        try {
+            success = mIWm.mirrorDisplay(mDisplayId, mSurfaceControl);
+        } catch (RemoteException e) {
+        }
+
+        if (!success) {
+            return;
+        }
+
+        if (!mSurfaceControl.isValid()) {
+            return;
+        }
+
+        mHasMirror = true;
+
+        mBorderSc = new SurfaceControl.Builder()
+                .setName("Mirror Border")
+                .setBufferSize(1, 1)
+                .setFormat(PixelFormat.TRANSLUCENT)
+                .build();
+
+        updateMirror(displayFrame, scale);
+
+        mTransaction
+                .show(mSurfaceControl)
+                .reparent(mSurfaceControl, mOverlayView.getViewRootImpl().getSurfaceControl())
+                .setLayer(mBorderSc, 1)
+                .show(mBorderSc)
+                .reparent(mBorderSc, mSurfaceControl)
+                .apply();
+    }
+
+    private void updateMirror(Rect displayFrame, float scale) {
+        if (displayFrame.isEmpty()) {
+            Rect bounds = mDisplayBounds;
+            int defaultCropW = Math.round(bounds.width() / 2);
+            int defaultCropH = Math.round(bounds.height() / 2);
+            displayFrame.set(0, 0, defaultCropW, defaultCropH);
+        }
+
+        if (scale <= 0) {
+            scale = DEFAULT_SCALE;
+        }
+
+        mCurrFrame.set(displayFrame);
+        mCurrScale = scale;
+
+        int width = (int) Math.ceil(displayFrame.width() / scale);
+        int height = (int) Math.ceil(displayFrame.height() / scale);
+
+        Rect sourceBounds = getSourceBounds(displayFrame, scale);
+
+        mTransaction.setGeometry(mSurfaceControl, sourceBounds, displayFrame, Surface.ROTATION_0)
+                .setPosition(mBorderSc, sourceBounds.left, sourceBounds.top)
+                .setBufferSize(mBorderSc, width, height)
+                .apply();
+
+        drawBorder(mBorderSc, width, height, (int) Math.ceil(BORDER_SIZE / scale));
+
+        mSourcePositionText.setText(sourceBounds.left + ", " + sourceBounds.top);
+        mDisplayFrameText.setText(
+                String.format("%s, %s, %s, %s", mCurrFrame.left, mCurrFrame.top, mCurrFrame.right,
+                        mCurrFrame.bottom));
+        mScaleText.setText(String.valueOf(mCurrScale));
+    }
+
+    private void drawBorder(SurfaceControl borderSc, int width, int height, int borderSize) {
+        mTmpSurface.copyFrom(borderSc);
+
+        Canvas c = null;
+        try {
+            c = mTmpSurface.lockCanvas(null);
+        } catch (IllegalArgumentException | Surface.OutOfResourcesException e) {
+        }
+        if (c == null) {
+            return;
+        }
+
+        // Top
+        c.save();
+        c.clipRect(new Rect(0, 0, width, borderSize));
+        c.drawColor(DEFAULT_BORDER_COLOR);
+        c.restore();
+        // Left
+        c.save();
+        c.clipRect(new Rect(0, 0, borderSize, height));
+        c.drawColor(DEFAULT_BORDER_COLOR);
+        c.restore();
+        // Right
+        c.save();
+        c.clipRect(new Rect(width - borderSize, 0, width, height));
+        c.drawColor(DEFAULT_BORDER_COLOR);
+        c.restore();
+        // Bottom
+        c.save();
+        c.clipRect(new Rect(0, height - borderSize, width, height));
+        c.drawColor(DEFAULT_BORDER_COLOR);
+        c.restore();
+
+        mTmpSurface.unlockCanvasAndPost(c);
+    }
+
+    @Override
+    public void onClick(View v) {
+        Point offset = findOffset(v);
+        moveMirrorForArrows(offset.x, offset.y);
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        mIsPressedDown = true;
+        Point point = findOffset(v);
+        mMoveMirrorRunnable.mXOffset = point.x;
+        mMoveMirrorRunnable.mYOffset = point.y;
+        mHandler.post(mMoveMirrorRunnable);
+        return false;
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mIsPressedDown = false;
+                break;
+        }
+        return false;
+    }
+
+    private Point findOffset(View v) {
+        Point offset = new Point(0, 0);
+
+        switch (v.getId()) {
+            case R.id.up_arrow:
+                offset.y = -MOVE_FRAME_AMOUNT;
+                break;
+            case R.id.down_arrow:
+                offset.y = MOVE_FRAME_AMOUNT;
+                break;
+            case R.id.right_arrow:
+                offset.x = -MOVE_FRAME_AMOUNT;
+                break;
+            case R.id.left_arrow:
+                offset.x = MOVE_FRAME_AMOUNT;
+                break;
+        }
+
+        return offset;
+    }
+
+    private void moveMirrorForArrows(int xOffset, int yOffset) {
+        mCurrFrame.offset(xOffset, yOffset);
+
+        updateMirror(mCurrFrame, mCurrScale);
+    }
+
+    /**
+     * Calculates the desired source bounds. This will be the area under from the center of  the
+     * displayFrame, factoring in scale.
+     */
+    private Rect getSourceBounds(Rect displayFrame, float scale) {
+        int halfWidth = displayFrame.width() / 2;
+        int halfHeight = displayFrame.height() / 2;
+        int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
+        int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale));
+        int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
+        int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
+        return new Rect(left, top, right, bottom);
+    }
+
+    class MoveMirrorRunnable implements Runnable {
+        int mXOffset = 0;
+        int mYOffset = 0;
+
+        @Override
+        public void run() {
+            if (mIsPressedDown) {
+                moveMirrorForArrows(mXOffset, mYOffset);
+                mHandler.postDelayed(mMoveMirrorRunnable, 150);
+            }
+        }
+    }
+}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index 2adbb06..46e27c1 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -18,7 +18,6 @@
 
 import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
 import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.AF_INET;
 import static android.system.OsConstants.AF_INET6;
 import static android.system.OsConstants.IPPROTO_TCP;
@@ -28,6 +27,7 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -152,9 +152,13 @@
 
     private void checkConnectionOwnerUid(int protocol, InetSocketAddress local,
                                          InetSocketAddress remote, boolean expectSuccess) {
-        final int expectedUid = expectSuccess ? Process.myUid() : INVALID_UID;
         final int uid = mCm.getConnectionOwnerUid(protocol, local, remote);
-        assertEquals(expectedUid, uid);
+
+        if (expectSuccess) {
+            assertEquals(Process.myUid(), uid);
+        } else {
+            assertNotEquals(Process.myUid(), uid);
+        }
     }
 
     private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception {
@@ -165,11 +169,11 @@
         return localPort;
     }
 
+    /**
+     * Create a test connection for UDP and TCP sockets and verify that this
+     * {protocol, local, remote} socket result in receiving a valid UID.
+     */
     public void checkGetConnectionOwnerUid(String to, String from) throws Exception {
-        /**
-         * For TCP connections, create a test connection and verify that this
-         * {protocol, local, remote} socket result in receiving a valid UID.
-         */
         TcpConnection tcp = new TcpConnection(to, from);
         checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true);
         checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false);
@@ -177,20 +181,14 @@
         checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false);
         tcp.close();
 
-        /**
-         * For UDP connections, either a complete match {protocol, local, remote} or a
-         * partial match {protocol, local} should return a valid UID.
-         */
         UdpConnection udp = new UdpConnection(to,from);
         checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true);
-        checkConnectionOwnerUid(udp.protocol, udp.local, new InetSocketAddress(0), true);
         checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false);
         checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)),
                 udp.remote, false);
         udp.close();
     }
 
-    @Ignore
     @Test
     public void testGetConnectionOwnerUid() throws Exception {
         checkGetConnectionOwnerUid("::", null);
@@ -203,6 +201,17 @@
         checkGetConnectionOwnerUid("::1", "::1");
     }
 
+    @Ignore("Times out on Marlin/Sailfish")
+    /* Verify fix for b/141603906 */
+    @Test
+    public void testB141603906() throws Exception {
+        final InetSocketAddress src = new InetSocketAddress(0);
+        final InetSocketAddress dst = new InetSocketAddress(0);
+        for (int i = 1; i <= 100000; i++) {
+            mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst);
+        }
+    }
+
     // Hexadecimal representation of InetDiagReqV2 request.
     private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX =
             // struct nlmsghdr
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 9e21db7..5bfd647 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -258,13 +258,13 @@
     private static final String TAG = "ConnectivityServiceTest";
 
     private static final int TIMEOUT_MS = 500;
-    private static final int TEST_LINGER_DELAY_MS = 250;
+    private static final int TEST_LINGER_DELAY_MS = 300;
     // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
     // LOST callback that arrives immediately and a LOST callback that arrives after the linger
     // timeout. For this, our assertions should run fast enough to leave less than
     // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
     // supposedly fired, and the time we call expectCallback.
-    private static final int TEST_CALLBACK_TIMEOUT_MS = 200;
+    private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
     // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
     // complete before callbacks are verified.
     private static final int TEST_REQUEST_TIMEOUT_MS = 150;
@@ -1466,6 +1466,10 @@
      * received. assertNoCallback may be called at any time.
      */
     private class TestNetworkCallback extends TestableNetworkCallback {
+        TestNetworkCallback() {
+            super(TEST_CALLBACK_TIMEOUT_MS);
+        }
+
         @Override
         public void assertNoCallback() {
             // TODO: better support this use case in TestableNetworkCallback
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index cd2bd26..7029218 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -561,11 +561,17 @@
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{SYSTEM_UID1});
     }
 
-    private PackageInfo addPackage(String packageName, int uid, String[] permissions)
+    private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
             throws Exception {
         PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM);
         when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
         when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
+        return packageInfo;
+    }
+
+    private PackageInfo addPackage(String packageName, int uid, String[] permissions)
+            throws Exception {
+        PackageInfo packageInfo = setPackagePermissions(packageName, uid, permissions);
         mObserver.onPackageAdded(packageName, uid);
         return packageInfo;
     }
@@ -616,14 +622,13 @@
     }
 
     @Test
-    public void testPackageUpdate() throws Exception {
+    public void testPackageRemoveThenAdd() throws Exception {
         final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
 
         addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
                 | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
 
-        // Remove and install the same package to simulate the update action
         when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
         mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
         mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
@@ -633,6 +638,20 @@
     }
 
     @Test
+    public void testPackageUpdate() throws Exception {
+        final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+        addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {});
+        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_NONE, new int[]{MOCK_UID1});
+
+        // When updating a package, the broadcast receiver gets two broadcasts (a remove and then an
+        // add), but the observer sees only one callback (an update).
+        setPackagePermissions(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
+        mObserver.onPackageChanged(MOCK_PACKAGE1, MOCK_UID1);
+        mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+    }
+
+    @Test
     public void testPackageUninstallWithMultiplePackages() throws Exception {
         final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
 
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 7966ba2..8a43bb4 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -169,17 +169,12 @@
   aapt::text::Printer printer(&fout);
 
   aapt::StdErrDiagnostics diagnostics;
-  auto main_command = new aapt::MainCommand(&printer, &diagnostics);
+  aapt::MainCommand main_command(&printer, &diagnostics);
 
   // Add the daemon subcommand here so it cannot be called while executing the daemon
-  main_command->AddOptionalSubcommand(
+  main_command.AddOptionalSubcommand(
       aapt::util::make_unique<aapt::DaemonCommand>(&fout, &diagnostics));
-  return main_command->Execute(args, &std::cerr);
-}
-
-// TODO(b/141312058) stop leaks
-extern "C" const char *__asan_default_options() {
-    return "detect_leaks=0";
+  return main_command.Execute(args, &std::cerr);
 }
 
 int main(int argc, char** argv) {
diff --git a/tools/codegen/src/com/android/codegen/Main.kt b/tools/codegen/src/com/android/codegen/Main.kt
index fa2b41a..5804674 100755
--- a/tools/codegen/src/com/android/codegen/Main.kt
+++ b/tools/codegen/src/com/android/codegen/Main.kt
@@ -132,11 +132,11 @@
         // $GENERATED_WARNING_PREFIX v$CODEGEN_VERSION.
         //
         // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
         //
         // To regenerate run:
         // $ $cliExecutable ${cliArgs.dropLast(1).joinToString("") { "$it " }}$fileEscaped
-        //
-        // CHECKSTYLE:OFF Generated code
+
         """
 
         if (FeatureFlag.CONST_DEFS()) generateConstDefs()
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index b2cc813..1e3973e 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
 package com.android.codegen
 
 const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.1"
+const val CODEGEN_VERSION = "1.0.3"
 
 const val CANONICAL_BUILDER_CLASS = "Builder"
 const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/protologtool/README.md b/tools/protologtool/README.md
index 3439357..ba63957 100644
--- a/tools/protologtool/README.md
+++ b/tools/protologtool/README.md
@@ -8,8 +8,13 @@
 
 ### Code transformation
 
-Command: `process <protolog class path> <protolog implementation class path>
- <protolog groups class path> <config.jar> [<input.java>] <output.srcjar>`
+Command: `protologtool transform-protolog-calls 
+    --protolog-class <protolog class name> 
+    --protolog-impl-class <protolog implementation class name>
+    --loggroups-class <protolog groups class name>
+    --loggroups-jar <config jar path>
+    --output-srcjar <output.srcjar>
+    [<input.java>]`
 
 In this mode ProtoLogTool transforms every ProtoLog logging call in form of:
 ```java
@@ -17,16 +22,20 @@
 ```
 into:
 ```java
-if (GROUP_NAME.isLogToAny()) {
-    ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 123456, "Format string %d %s or null", value1, value2);
+if (ProtoLogImpl.isEnabled(GROUP_NAME)) {
+    int protoLogParam0 = value1;
+    String protoLogParam1 = String.valueOf(value2);
+    ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 123456, 0b0100, "Format string %d %s or null", protoLogParam0, protoLogParam1);
 }
 ```
 where `ProtoLog`, `ProtoLogImpl` and `ProtoLogGroup` are the classes provided as arguments
  (can be imported, static imported or full path, wildcard imports are not allowed) and, `x` is the
  logging method. The transformation is done on the source level. A hash is generated from the format
- string and log level and inserted after the `ProtoLogGroup` argument. The format string is replaced
+ string, log level and log group name and inserted after the `ProtoLogGroup` argument. After the hash
+ we insert a bitmask specifying the types of logged parameters. The format string is replaced
  by `null` if `ProtoLogGroup.GROUP_NAME.isLogToLogcat()` returns false. If `ProtoLogGroup.GROUP_NAME.isEnabled()`
- returns false the log statement is removed entirely from the resultant code.
+ returns false the log statement is removed entirely from the resultant code. The real generated code is inlined
+ and a number of new line characters is added as to preserve line numbering in file.
 
 Input is provided as a list of java source file names. Transformed source is saved to a single
 source jar file. The ProtoLogGroup class with all dependencies should be provided as a compiled
@@ -34,8 +43,12 @@
 
 ### Viewer config generation
 
-Command: `viewerconf <protolog class path> <protolog implementation class path
-<protolog groups class path> <config.jar> [<input.java>] <output.json>`
+Command: `generate-viewer-config
+    --protolog-class <protolog class name> 
+    --loggroups-class <protolog groups class name>
+    --loggroups-jar <config jar path>
+    --viewer-conf <viewer.json>
+    [<input.java>]`
 
 This command is similar in it's syntax to the previous one, only instead of creating a processed source jar
 it writes a viewer configuration file with following schema:
@@ -46,8 +59,9 @@
     "123456": {
       "message": "Format string %d %s",
       "level": "ERROR",
-      "group": "GROUP_NAME"
-    },
+      "group": "GROUP_NAME",
+      "at": "com\/android\/server\/example\/Class.java"
+    }
   },
   "groups": {
     "GROUP_NAME": {
@@ -60,13 +74,13 @@
 
 ### Binary log viewing
 
-Command: `read <viewer.json> <wm_log.pb>`
+Command: `read-log --viewer-conf <viewer.json> <wm_log.pb>`
 
 Reads the binary ProtoLog log file and outputs a human-readable LogCat-like text log.
 
 ## What is ProtoLog?
 
-ProtoLog is a logging system created for the WindowManager project. It allows both binary and text logging
+ProtoLog is a generic logging system created for the WindowManager project. It allows both binary and text logging
 and is tunable in runtime. It consists of 3 different submodules:
 * logging system built-in the Android app,
 * log viewer for reading binary logs,
@@ -94,8 +108,7 @@
 
 To add a new logging statement just add a new call to ProtoLog.x where x is a log level.
 
-After doing any changes to logging groups or statements you should run `make update-protolog` to update
-viewer configuration saved in the code repository.
+After doing any changes to logging groups or statements you should build the project and follow instructions printed by the tool.
 
 ## How to change settings on device in runtime?
 Use the `adb shell su root cmd window logging` command. To get help just type
diff --git a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
index cb29508..a52c804 100644
--- a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
@@ -20,7 +20,6 @@
 import com.github.javaparser.ast.ImportDeclaration
 import com.github.javaparser.ast.expr.BinaryExpr
 import com.github.javaparser.ast.expr.Expression
-import com.github.javaparser.ast.expr.MethodCallExpr
 import com.github.javaparser.ast.expr.StringLiteralExpr
 
 object CodeUtils {
@@ -33,9 +32,14 @@
                 .map { c -> c.toInt() }.reduce { h, c -> h * 31 + c }
     }
 
-    fun isWildcardStaticImported(code: CompilationUnit, className: String): Boolean {
-        return code.findAll(ImportDeclaration::class.java)
-                .any { im -> im.isStatic && im.isAsterisk && im.name.toString() == className }
+    fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) {
+        code.findAll(ImportDeclaration::class.java)
+                .forEach { im ->
+                    if (im.isStatic && im.isAsterisk && im.name.toString() == className) {
+                        throw IllegalImportException("Wildcard static imports of $className " +
+                                "methods are not supported.", ParsingContext(fileName, im))
+                    }
+                }
     }
 
     fun isClassImportedOrSamePackage(code: CompilationUnit, className: String): Boolean {
@@ -59,25 +63,19 @@
                 .map { im -> im.name.toString().substringAfterLast('.') }.toSet()
     }
 
-    fun concatMultilineString(expr: Expression): String {
+    fun concatMultilineString(expr: Expression, context: ParsingContext): String {
         return when (expr) {
             is StringLiteralExpr -> expr.asString()
             is BinaryExpr -> when {
                 expr.operator == BinaryExpr.Operator.PLUS ->
-                    concatMultilineString(expr.left) + concatMultilineString(expr.right)
+                    concatMultilineString(expr.left, context) +
+                            concatMultilineString(expr.right, context)
                 else -> throw InvalidProtoLogCallException(
-                        "messageString must be a string literal " +
-                                "or concatenation of string literals.", expr)
+                        "expected a string literal " +
+                                "or concatenation of string literals, got: $expr", context)
             }
-            else -> throw InvalidProtoLogCallException("messageString must be a string literal " +
-                    "or concatenation of string literals.", expr)
-        }
-    }
-
-    fun getPositionString(call: MethodCallExpr, fileName: String): String {
-        return when {
-            call.range.isPresent -> "$fileName:${call.range.get().begin.line}"
-            else -> fileName
+            else -> throw InvalidProtoLogCallException("expected a string literal " +
+                    "or concatenation of string literals, got: $expr", context)
         }
     }
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt
index 7759f35..e88f0f8 100644
--- a/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/LogLevel.kt
@@ -22,7 +22,7 @@
     DEBUG, VERBOSE, INFO, WARN, ERROR, WTF;
 
     companion object {
-        fun getLevelForMethodName(name: String, node: Node): LogLevel {
+        fun getLevelForMethodName(name: String, node: Node, context: ParsingContext): LogLevel {
             return when (name) {
                 "d" -> DEBUG
                 "v" -> VERBOSE
@@ -30,7 +30,8 @@
                 "w" -> WARN
                 "e" -> ERROR
                 "wtf" -> WTF
-                else -> throw InvalidProtoLogCallException("Unknown log level $name", node)
+                else ->
+                    throw InvalidProtoLogCallException("Unknown log level $name in $node", context)
             }
         }
     }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ParsingContext.kt b/tools/protologtool/src/com/android/protolog/tool/ParsingContext.kt
new file mode 100644
index 0000000..c6aedfc
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ParsingContext.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.protolog.tool
+
+import com.github.javaparser.ast.Node
+
+data class ParsingContext(val filePath: String, val lineNumber: Int) {
+    constructor(filePath: String, node: Node)
+            : this(filePath, if (node.range.isPresent) node.range.get().begin.line else -1)
+
+    constructor() : this("", -1)
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
index eae6396..2181cf6 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
@@ -38,23 +38,27 @@
     private fun getLogGroupName(
         expr: Expression,
         isClassImported: Boolean,
-        staticImports: Set<String>
+        staticImports: Set<String>,
+        fileName: String
     ): String {
+        val context = ParsingContext(fileName, expr)
         return when (expr) {
             is NameExpr -> when {
                 expr.nameAsString in staticImports -> expr.nameAsString
                 else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup", expr)
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
             }
             is FieldAccessExpr -> when {
                 expr.scope.toString() == protoLogGroupClassName
                         || isClassImported &&
                         expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString
                 else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup", expr)
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
             }
             else -> throw InvalidProtoLogCallException("Invalid group argument " +
-                    "- must be ProtoLogGroup enum member reference", expr)
+                    "- must be ProtoLogGroup enum member reference: $expr", context)
         }
     }
 
@@ -69,12 +73,10 @@
                 !call.scope.isPresent && staticLogImports.contains(call.name.toString())
     }
 
-    open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?): CompilationUnit {
-        if (CodeUtils.isWildcardStaticImported(code, protoLogClassName) ||
-                CodeUtils.isWildcardStaticImported(code, protoLogGroupClassName)) {
-            throw IllegalImportException("Wildcard static imports of $protoLogClassName " +
-                    "and $protoLogGroupClassName methods are not supported.")
-        }
+    open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String):
+            CompilationUnit {
+        CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
+        CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
 
         val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName)
         val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName)
@@ -86,22 +88,25 @@
                 .filter { call ->
                     isProtoCall(call, isLogClassImported, staticLogImports)
                 }.forEach { call ->
+                    val context = ParsingContext(fileName, call)
                     if (call.arguments.size < 2) {
                         throw InvalidProtoLogCallException("Method signature does not match " +
-                                "any ProtoLog method.", call)
+                                "any ProtoLog method: $call", context)
                     }
 
-                    val messageString = CodeUtils.concatMultilineString(call.getArgument(1))
+                    val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
+                            context)
                     val groupNameArg = call.getArgument(0)
                     val groupName =
-                            getLogGroupName(groupNameArg, isGroupClassImported, staticGroupImports)
+                            getLogGroupName(groupNameArg, isGroupClassImported,
+                                    staticGroupImports, fileName)
                     if (groupName !in groupMap) {
                         throw InvalidProtoLogCallException("Unknown group argument " +
-                                "- not a ProtoLogGroup enum member", call)
+                                "- not a ProtoLogGroup enum member: $call", context)
                     }
 
                     callVisitor?.processCall(call, messageString, LogLevel.getLevelForMethodName(
-                            call.name.toString(), call), groupMap.getValue(groupName))
+                            call.name.toString(), call, context), groupMap.getValue(groupName))
                 }
         return code
     }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index 53834a6..70ac0be 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -17,7 +17,9 @@
 package com.android.protolog.tool
 
 import com.android.protolog.tool.CommandOptions.Companion.USAGE
+import com.github.javaparser.ParseProblemException
 import com.github.javaparser.StaticJavaParser
+import com.github.javaparser.ast.CompilationUnit
 import java.io.File
 import java.io.FileInputStream
 import java.io.FileOutputStream
@@ -48,14 +50,19 @@
         command.javaSourceArgs.forEach { path ->
             val file = File(path)
             val text = file.readText()
-            val code = StaticJavaParser.parse(text)
-            val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
-                    .get().nameAsString else ""
-            val newPath = pack.replace('.', '/') + '/' + file.name
-            val outSrc = when {
-                containsProtoLogText(text, command.protoLogClassNameArg) ->
+            val newPath = path
+            val outSrc = try {
+                val code = tryParse(text, path)
+                if (containsProtoLogText(text, command.protoLogClassNameArg)) {
                     transformer.processClass(text, newPath, code)
-                else -> text
+                } else {
+                    text
+                }
+            } catch (ex: ParsingException) {
+                // If we cannot parse this file, skip it (and log why). Compilation will fail
+                // in a subsequent build step.
+                println("\n${ex.message}\n")
+                text
             }
             outJar.putNextEntry(ZipEntry(newPath))
             outJar.write(outSrc.toByteArray())
@@ -66,6 +73,19 @@
         out.close()
     }
 
+    private fun tryParse(code: String, fileName: String): CompilationUnit {
+        try {
+            return StaticJavaParser.parse(code)
+        } catch (ex: ParseProblemException) {
+            val problem = ex.problems.first()
+            throw ParsingException("Java parsing erro" +
+                    "r: ${problem.verboseMessage}",
+                    ParsingContext(fileName, problem.location.orElse(null)
+                            ?.begin?.range?.orElse(null)?.begin?.line
+                            ?: 0))
+        }
+    }
+
     private fun viewerConf(command: CommandOptions) {
         val groups = ProtoLogGroupReader()
                 .loadFromJar(command.protoLogGroupsJarArg, command.protoLogGroupsClassNameArg)
@@ -76,11 +96,17 @@
             val file = File(path)
             val text = file.readText()
             if (containsProtoLogText(text, command.protoLogClassNameArg)) {
-                val code = StaticJavaParser.parse(text)
-                val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
-                        .get().nameAsString else ""
-                val newPath = pack.replace('.', '/') + '/' + file.name
-                builder.processClass(code, newPath)
+                try {
+                    val code = tryParse(text, path)
+                    val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
+                            .get().nameAsString else ""
+                    val newPath = pack.replace('.', '/') + '/' + file.name
+                    builder.processClass(code, newPath)
+                } catch (ex: ParsingException) {
+                    // If we cannot parse this file, skip it (and log why). Compilation will fail
+                    // in a subsequent build step.
+                    println("\n${ex.message}\n")
+                }
             }
         }
         val out = FileOutputStream(command.viewerConfigJsonArg)
@@ -104,8 +130,11 @@
                 CommandOptions.READ_LOG_CMD -> read(command)
             }
         } catch (ex: InvalidCommandException) {
-            println(ex.message)
+            println("\n${ex.message}\n")
             showHelpAndExit()
+        } catch (ex: CodeProcessingException) {
+            println("\n${ex.message}\n")
+            exitProcess(1)
         }
     }
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index 3f38bc0..00fd038 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -73,8 +73,7 @@
         }
         val ifStmt: IfStmt
         if (group.enabled) {
-            val position = CodeUtils.getPositionString(call, fileName)
-            val hash = CodeUtils.hash(position, messageString, level, group)
+            val hash = CodeUtils.hash(fileName, messageString, level, group)
             val newCall = call.clone()
             if (!group.textEnabled) {
                 // Remove message string if text logging is not enabled by default.
@@ -99,7 +98,8 @@
                 NodeList<Expression>(newCall.arguments[0].clone()))
             if (argTypes.size != call.arguments.size - 2) {
                 throw InvalidProtoLogCallException(
-                        "Number of arguments does not mach format string", call)
+                        "Number of arguments (${argTypes.size} does not mach format" +
+                                " string in: $call", ParsingContext(fileName, call))
             }
             val blockStmt = BlockStmt()
             if (argTypes.isNotEmpty()) {
@@ -225,7 +225,7 @@
         processedCode = code.split('\n').toMutableList()
         offsets = IntArray(processedCode.size)
         LexicalPreservingPrinter.setup(compilationUnit)
-        protoLogCallProcessor.process(compilationUnit, this)
+        protoLogCallProcessor.process(compilationUnit, this, fileName)
         // return LexicalPreservingPrinter.print(compilationUnit)
         return processedCode.joinToString("\n")
     }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
index 4c41797..941455a 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
@@ -32,13 +32,14 @@
         group: LogGroup
     ) {
         if (group.enabled) {
-            val position = CodeUtils.getPositionString(call, fileName)
+            val position = fileName
             val key = CodeUtils.hash(position, messageString, level, group)
             if (statements.containsKey(key)) {
                 if (statements[key] != LogCall(messageString, level, group, position)) {
                     throw HashCollisionException(
                             "Please modify the log message \"$messageString\" " +
-                                    "or \"${statements[key]}\" - their hashes are equal.")
+                                    "or \"${statements[key]}\" - their hashes are equal.",
+                            ParsingContext(fileName, call))
                 }
             } else {
                 groups.add(group)
@@ -54,7 +55,7 @@
 
     fun processClass(unit: CompilationUnit, fileName: String) {
         this.fileName = fileName
-        protoLogCallVisitor.process(unit, this)
+        protoLogCallVisitor.process(unit, this, fileName)
     }
 
     fun build(): String {
diff --git a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt
index 0401d8f..ae00df1 100644
--- a/tools/protologtool/src/com/android/protolog/tool/exceptions.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/exceptions.kt
@@ -16,16 +16,23 @@
 
 package com.android.protolog.tool
 
-import com.github.javaparser.ast.Node
 import java.lang.Exception
-import java.lang.RuntimeException
 
-class HashCollisionException(message: String) : RuntimeException(message)
+open class CodeProcessingException(message: String, context: ParsingContext)
+    : Exception("Code processing error in ${context.filePath}:${context.lineNumber}:\n" +
+        "  $message")
 
-class IllegalImportException(message: String) : Exception(message)
+class HashCollisionException(message: String, context: ParsingContext) :
+        CodeProcessingException(message, context)
 
-class InvalidProtoLogCallException(message: String, node: Node)
-    : RuntimeException("$message\nAt: $node")
+class IllegalImportException(message: String, context: ParsingContext) :
+        CodeProcessingException("Illegal import: $message", context)
+
+class InvalidProtoLogCallException(message: String, context: ParsingContext)
+    : CodeProcessingException("InvalidProtoLogCall: $message", context)
+
+class ParsingException(message: String, context: ParsingContext)
+    : CodeProcessingException(message, context)
 
 class InvalidViewerConfigException(message: String) : Exception(message)
 
diff --git a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
index 0acbc90..b916f8f 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
@@ -55,40 +55,40 @@
                 LogLevel.DEBUG, LogGroup("test2", true, true, "TAG")))
     }
 
-    @Test
-    fun isWildcardStaticImported_true() {
+    @Test(expected = IllegalImportException::class)
+    fun checkWildcardStaticImported_true() {
         val code = """package org.example.test;
             import static org.example.Test.*;
         """
-        assertTrue(CodeUtils.isWildcardStaticImported(
-                StaticJavaParser.parse(code), "org.example.Test"))
+        CodeUtils.checkWildcardStaticImported(
+                StaticJavaParser.parse(code), "org.example.Test", "")
     }
 
     @Test
-    fun isWildcardStaticImported_notStatic() {
+    fun checkWildcardStaticImported_notStatic() {
         val code = """package org.example.test;
             import org.example.Test.*;
         """
-        assertFalse(CodeUtils.isWildcardStaticImported(
-                StaticJavaParser.parse(code), "org.example.Test"))
+        CodeUtils.checkWildcardStaticImported(
+                StaticJavaParser.parse(code), "org.example.Test", "")
     }
 
     @Test
-    fun isWildcardStaticImported_differentClass() {
+    fun checkWildcardStaticImported_differentClass() {
         val code = """package org.example.test;
             import static org.example.Test2.*;
         """
-        assertFalse(CodeUtils.isWildcardStaticImported(
-                StaticJavaParser.parse(code), "org.example.Test"))
+        CodeUtils.checkWildcardStaticImported(
+                StaticJavaParser.parse(code), "org.example.Test", "")
     }
 
     @Test
-    fun isWildcardStaticImported_notWildcard() {
+    fun checkWildcardStaticImported_notWildcard() {
         val code = """package org.example.test;
             import org.example.Test.test;
         """
-        assertFalse(CodeUtils.isWildcardStaticImported(
-                StaticJavaParser.parse(code), "org.example.Test"))
+        CodeUtils.checkWildcardStaticImported(
+                StaticJavaParser.parse(code), "org.example.Test", "")
     }
 
     @Test
@@ -156,7 +156,7 @@
     @Test
     fun concatMultilineString_single() {
         val str = StringLiteralExpr("test")
-        val out = CodeUtils.concatMultilineString(str)
+        val out = CodeUtils.concatMultilineString(str, ParsingContext())
         assertEquals("test", out)
     }
 
@@ -166,7 +166,7 @@
             "test" + "abc"
         """
         val code = StaticJavaParser.parseExpression<BinaryExpr>(str)
-        val out = CodeUtils.concatMultilineString(code)
+        val out = CodeUtils.concatMultilineString(code, ParsingContext())
         assertEquals("testabc", out)
     }
 
@@ -176,7 +176,7 @@
             "test" + "abc" + "1234" + "test"
         """
         val code = StaticJavaParser.parseExpression<BinaryExpr>(str)
-        val out = CodeUtils.concatMultilineString(code)
+        val out = CodeUtils.concatMultilineString(code, ParsingContext())
         assertEquals("testabc1234test", out)
     }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
index d20ce7e..97f67a0 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
@@ -66,7 +66,7 @@
         """
         groupMap["TEST"] = LogGroup("TEST", true, false, "WindowManager")
         groupMap["ERROR"] = LogGroup("ERROR", true, true, "WindowManagerERROR")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
         assertEquals(2, calls.size)
         var c = calls[0]
         assertEquals("test %b", c.messageString)
@@ -93,7 +93,7 @@
             }
         """
         groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
         checkCalls()
     }
 
@@ -112,7 +112,7 @@
             }
         """
         groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
         checkCalls()
     }
 
@@ -130,7 +130,7 @@
             }
         """
         groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
     }
 
     @Test
@@ -147,7 +147,7 @@
             }
         """
         groupMap["TEST"] = LogGroup("TEST", true, true, "WindowManager")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
         assertEquals(0, calls.size)
     }
 
@@ -162,7 +162,7 @@
                 }
             }
         """
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
     }
 
     @Test(expected = InvalidProtoLogCallException::class)
@@ -176,7 +176,7 @@
                 }
             }
         """
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
     }
 
     @Test(expected = InvalidProtoLogCallException::class)
@@ -190,7 +190,7 @@
                 }
             }
         """
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
     }
 
     @Test(expected = InvalidProtoLogCallException::class)
@@ -204,7 +204,7 @@
                 }
             }
         """
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
     }
 
     @Test
@@ -220,7 +220,7 @@
             }
         """
         groupMap["TEST"] = LogGroup("TEST", false, true, "WindowManager")
-        visitor.process(StaticJavaParser.parse(code), processor)
+        visitor.process(StaticJavaParser.parse(code), processor, "")
         checkCalls()
     }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index f221fbd..e746300 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -78,7 +78,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -88,7 +88,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 805272208, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
@@ -100,8 +100,8 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, "test %d %f", protoLogParam0, protoLogParam1); }
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -154595499, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -111,7 +111,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { org.example.ProtoLogImpl.w(TEST_GROUP, 1913810354, 0, "test", (Object[]) null); }
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); }
                 }
             }
             """.trimIndent()
@@ -121,7 +121,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1922613844, 9, null, protoLogParam0, protoLogParam1); }
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -131,7 +131,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 805272208, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
+                    if (org.example.ProtoLogImpl.isEnabled(TEST_GROUP)) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
@@ -175,7 +175,8 @@
         var code = StaticJavaParser.parse(TEST_CODE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -199,7 +200,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1922613844", methodCall.arguments[1].toString())
+        assertEquals("1698911065", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -212,7 +213,8 @@
         var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             val calls = code.findAll(MethodCallExpr::class.java)
@@ -241,7 +243,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1922613844", methodCall.arguments[1].toString())
+        assertEquals("1698911065", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -254,7 +256,8 @@
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -279,7 +282,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("805272208", methodCall.arguments[1].toString())
+        assertEquals("1780316587", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
         assertEquals("protoLogParam1", methodCall.arguments[5].toString())
@@ -292,7 +295,8 @@
         var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test",
@@ -316,7 +320,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(5, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1913810354", methodCall.arguments[1].toString())
+        assertEquals("-1741986185", methodCall.arguments[1].toString())
         assertEquals(0.toString(), methodCall.arguments[2].toString())
         assertEquals(TRANSFORMED_CODE_NO_PARAMS, out)
     }
@@ -326,7 +330,8 @@
         var code = StaticJavaParser.parse(TEST_CODE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -350,7 +355,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1922613844", methodCall.arguments[1].toString())
+        assertEquals("1698911065", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -363,7 +368,8 @@
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -388,7 +394,7 @@
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("805272208", methodCall.arguments[1].toString())
+        assertEquals("1780316587", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -402,7 +408,8 @@
         var code = StaticJavaParser.parse(TEST_CODE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -426,7 +433,8 @@
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
index d3f8c76..2b6abcd 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
@@ -50,7 +50,8 @@
     @Test
     fun processClass() {
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
@@ -78,7 +79,8 @@
     @Test
     fun processClass_nonUnique() {
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
@@ -102,7 +104,8 @@
     @Test
     fun processClass_disabled() {
         Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
+                .thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(MethodCallExpr(), TEST1.messageString, LogLevel.INFO,
diff --git a/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl
new file mode 100644
index 0000000..b83b594
--- /dev/null
+++ b/wifi/java/android/net/wifi/ILocalOnlyHotspotCallback.aidl
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.net.wifi.WifiConfiguration;
+
+/**
+ * Communicates LOHS status back to the application process.
+ *
+ * @hide
+ */
+oneway interface ILocalOnlyHotspotCallback {
+    void onHotspotStarted(in WifiConfiguration config);
+    void onHotspotStopped();
+    void onHotspotFailed(int reason);
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index a97a5a5..b7e1094 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -26,6 +26,7 @@
 import android.net.Network;
 import android.net.wifi.IActionListener;
 import android.net.wifi.IDppCallback;
+import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.ISoftApCallback;
 import android.net.wifi.ITrafficStateCallback;
@@ -138,11 +139,11 @@
 
     boolean stopSoftAp();
 
-    int startLocalOnlyHotspot(in Messenger messenger, in IBinder binder, String packageName);
+    int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName);
 
     void stopLocalOnlyHotspot();
 
-    void startWatchLocalOnlyHotspot(in Messenger messenger, in IBinder binder);
+    void startWatchLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback);
 
     void stopWatchLocalOnlyHotspot();
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index eb5a717..2afb14a 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1056,26 +1056,6 @@
     }
 
     /**
-     * @hide
-     * Returns Randomized MAC address to use with the network.
-     * If it is not set/valid, creates a new randomized address.
-     * If it can't generate a valid mac, returns the default MAC.
-     */
-    public @NonNull MacAddress getOrCreateRandomizedMacAddress() {
-        int randomMacGenerationCount = 0;
-        while (!isValidMacAddressForRandomization(mRandomizedMacAddress)
-                && randomMacGenerationCount < MAXIMUM_RANDOM_MAC_GENERATION_RETRY) {
-            mRandomizedMacAddress = MacAddress.createRandomUnicastAddress();
-            randomMacGenerationCount++;
-        }
-
-        if (!isValidMacAddressForRandomization(mRandomizedMacAddress)) {
-            mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
-        }
-        return mRandomizedMacAddress;
-    }
-
-    /**
      * Returns MAC address set to be the local randomized MAC address.
      * Depending on user preference, the device may or may not use the returned MAC address for
      * connections to this network.
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 00895e8..5782f5b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -45,10 +45,9 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.WorkSource;
@@ -1127,16 +1126,6 @@
     private Looper mLooper;
     private boolean mVerboseLoggingEnabled = false;
 
-    /* LocalOnlyHotspot callback message types */
-    /** @hide */
-    public static final int HOTSPOT_STARTED = 0;
-    /** @hide */
-    public static final int HOTSPOT_STOPPED = 1;
-    /** @hide */
-    public static final int HOTSPOT_FAILED = 2;
-    /** @hide */
-    public static final int HOTSPOT_OBSERVER_REGISTERED = 3;
-
     private final Object mLock = new Object(); // lock guarding access to the following vars
     @GuardedBy("mLock")
     private LocalOnlyHotspotCallbackProxy mLOHSCallbackProxy;
@@ -2730,6 +2719,13 @@
         }
     }
 
+    private Executor executorForHandler(@Nullable Handler handler) {
+        if (handler == null) {
+            return mContext.getMainExecutor();
+        }
+        return new HandlerExecutor(handler);
+    }
+
     /**
      * Request a local only hotspot that an application can use to communicate between co-located
      * devices connected to the created WiFi hotspot.  The network created by this method will not
@@ -2787,21 +2783,20 @@
      */
     public void startLocalOnlyHotspot(LocalOnlyHotspotCallback callback,
             @Nullable Handler handler) {
+        Executor executor = executorForHandler(handler);
         synchronized (mLock) {
-            Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
             LocalOnlyHotspotCallbackProxy proxy =
-                    new LocalOnlyHotspotCallbackProxy(this, looper, callback);
+                    new LocalOnlyHotspotCallbackProxy(this, executor, callback);
             try {
                 IWifiManager iWifiManager = getIWifiManager();
                 if (iWifiManager == null) {
                     throw new RemoteException("Wifi service is not running");
                 }
                 String packageName = mContext.getOpPackageName();
-                int returnCode = iWifiManager.startLocalOnlyHotspot(
-                        proxy.getMessenger(), new Binder(), packageName);
+                int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName);
                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
                     // Send message to the proxy to make sure we call back on the correct thread
-                    proxy.notifyFailed(returnCode);
+                    proxy.onHotspotFailed(returnCode);
                     return;
                 }
                 mLOHSCallbackProxy = proxy;
@@ -2879,16 +2874,16 @@
      */
     public void watchLocalOnlyHotspot(LocalOnlyHotspotObserver observer,
             @Nullable Handler handler) {
+        Executor executor = executorForHandler(handler);
         synchronized (mLock) {
-            Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
-            mLOHSObserverProxy = new LocalOnlyHotspotObserverProxy(this, looper, observer);
+            mLOHSObserverProxy =
+                    new LocalOnlyHotspotObserverProxy(this, executor, observer);
             try {
                 IWifiManager iWifiManager = getIWifiManager();
                 if (iWifiManager == null) {
                     throw new RemoteException("Wifi service is not running");
                 }
-                iWifiManager.startWatchLocalOnlyHotspot(
-                        mLOHSObserverProxy.getMessenger(), new Binder());
+                iWifiManager.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
                 mLOHSObserverProxy.registered();
             } catch (RemoteException e) {
                 mLOHSObserverProxy = null;
@@ -3446,82 +3441,58 @@
     /**
      * Callback proxy for LocalOnlyHotspotCallback objects.
      */
-    private static class LocalOnlyHotspotCallbackProxy {
-        private final Handler mHandler;
+    private static class LocalOnlyHotspotCallbackProxy extends ILocalOnlyHotspotCallback.Stub {
         private final WeakReference<WifiManager> mWifiManager;
-        private final Looper mLooper;
-        private final Messenger mMessenger;
+        private final Executor mExecutor;
+        private final LocalOnlyHotspotCallback mCallback;
 
         /**
-         * Constructs a {@link LocalOnlyHotspotCallback} using the specified looper.  All callbacks
-         * will be delivered on the thread of the specified looper.
+         * Constructs a {@link LocalOnlyHotspotCallbackProxy} using the specified executor.  All
+         * callbacks will run using the given executor.
          *
          * @param manager WifiManager
-         * @param looper Looper for delivering callbacks
+         * @param executor Executor for delivering callbacks.
          * @param callback LocalOnlyHotspotCallback to notify the calling application.
          */
-        LocalOnlyHotspotCallbackProxy(WifiManager manager, Looper looper,
-                final LocalOnlyHotspotCallback callback) {
+        LocalOnlyHotspotCallbackProxy(WifiManager manager, Executor executor,
+                                      LocalOnlyHotspotCallback callback) {
             mWifiManager = new WeakReference<>(manager);
-            mLooper = looper;
-
-            mHandler = new Handler(looper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    Log.d(TAG, "LocalOnlyHotspotCallbackProxy: handle message what: "
-                            + msg.what + " msg: " + msg);
-
-                    WifiManager manager = mWifiManager.get();
-                    if (manager == null) {
-                        Log.w(TAG, "LocalOnlyHotspotCallbackProxy: handle message post GC");
-                        return;
-                    }
-
-                    switch (msg.what) {
-                        case HOTSPOT_STARTED:
-                            WifiConfiguration config = (WifiConfiguration) msg.obj;
-                            if (config == null) {
-                                Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
-                                callback.onFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
-                                return;
-                            }
-                            callback.onStarted(manager.new LocalOnlyHotspotReservation(config));
-                            break;
-                        case HOTSPOT_STOPPED:
-                            Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
-                            callback.onStopped();
-                            break;
-                        case HOTSPOT_FAILED:
-                            int reasonCode = msg.arg1;
-                            Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
-                                    + reasonCode);
-                            callback.onFailed(reasonCode);
-                            Log.w(TAG, "done with the callback...");
-                            break;
-                        default:
-                            Log.e(TAG, "LocalOnlyHotspotCallbackProxy unhandled message.  type: "
-                                    + msg.what);
-                    }
-                }
-            };
-            mMessenger = new Messenger(mHandler);
+            mExecutor = executor;
+            mCallback = callback;
         }
 
-        public Messenger getMessenger() {
-            return mMessenger;
+        @Override
+        public void onHotspotStarted(WifiConfiguration config) {
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            if (config == null) {
+                Log.e(TAG, "LocalOnlyHotspotCallbackProxy: config cannot be null.");
+                onHotspotFailed(LocalOnlyHotspotCallback.ERROR_GENERIC);
+                return;
+            }
+            final LocalOnlyHotspotReservation reservation =
+                    manager.new LocalOnlyHotspotReservation(config);
+            mExecutor.execute(() -> mCallback.onStarted(reservation));
         }
 
-        /**
-         * Helper method allowing the the incoming application call to move the onFailed callback
-         * over to the desired callback thread.
-         *
-         * @param reason int representing the error type
-         */
-        public void notifyFailed(int reason) throws RemoteException {
-            Message msg = Message.obtain();
-            msg.what = HOTSPOT_FAILED;
-            msg.arg1 = reason;
-            mMessenger.send(msg);
+        @Override
+        public void onHotspotStopped() {
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            Log.w(TAG, "LocalOnlyHotspotCallbackProxy: hotspot stopped");
+            mExecutor.execute(() -> mCallback.onStopped());
+        }
+
+        @Override
+        public void onHotspotFailed(int reason) {
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            Log.w(TAG, "LocalOnlyHotspotCallbackProxy: failed to start.  reason: "
+                    + reason);
+            mExecutor.execute(() -> mCallback.onFailed(reason));
         }
     }
 
@@ -3589,69 +3560,57 @@
     /**
      * Callback proxy for LocalOnlyHotspotObserver objects.
      */
-    private static class LocalOnlyHotspotObserverProxy {
-        private final Handler mHandler;
+    private static class LocalOnlyHotspotObserverProxy extends ILocalOnlyHotspotCallback.Stub {
         private final WeakReference<WifiManager> mWifiManager;
-        private final Looper mLooper;
-        private final Messenger mMessenger;
+        private final Executor mExecutor;
+        private final LocalOnlyHotspotObserver mObserver;
 
         /**
          * Constructs a {@link LocalOnlyHotspotObserverProxy} using the specified looper.
          * All callbacks will be delivered on the thread of the specified looper.
          *
          * @param manager WifiManager
-         * @param looper Looper for delivering callbacks
+         * @param executor Executor for delivering callbacks
          * @param observer LocalOnlyHotspotObserver to notify the calling application.
          */
-        LocalOnlyHotspotObserverProxy(WifiManager manager, Looper looper,
+        LocalOnlyHotspotObserverProxy(WifiManager manager, Executor executor,
                 final LocalOnlyHotspotObserver observer) {
             mWifiManager = new WeakReference<>(manager);
-            mLooper = looper;
-
-            mHandler = new Handler(looper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    Log.d(TAG, "LocalOnlyHotspotObserverProxy: handle message what: "
-                            + msg.what + " msg: " + msg);
-
-                    WifiManager manager = mWifiManager.get();
-                    if (manager == null) {
-                        Log.w(TAG, "LocalOnlyHotspotObserverProxy: handle message post GC");
-                        return;
-                    }
-
-                    switch (msg.what) {
-                        case HOTSPOT_OBSERVER_REGISTERED:
-                            observer.onRegistered(manager.new LocalOnlyHotspotSubscription());
-                            break;
-                        case HOTSPOT_STARTED:
-                            WifiConfiguration config = (WifiConfiguration) msg.obj;
-                            if (config == null) {
-                                Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
-                                return;
-                            }
-                            observer.onStarted(config);
-                            break;
-                        case HOTSPOT_STOPPED:
-                            observer.onStopped();
-                            break;
-                        default:
-                            Log.e(TAG, "LocalOnlyHotspotObserverProxy unhandled message.  type: "
-                                    + msg.what);
-                    }
-                }
-            };
-            mMessenger = new Messenger(mHandler);
-        }
-
-        public Messenger getMessenger() {
-            return mMessenger;
+            mExecutor = executor;
+            mObserver = observer;
         }
 
         public void registered() throws RemoteException {
-            Message msg = Message.obtain();
-            msg.what = HOTSPOT_OBSERVER_REGISTERED;
-            mMessenger.send(msg);
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            mExecutor.execute(() ->
+                    mObserver.onRegistered(manager.new LocalOnlyHotspotSubscription()));
+        }
+
+        @Override
+        public void onHotspotStarted(WifiConfiguration config) {
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            if (config == null) {
+                Log.e(TAG, "LocalOnlyHotspotObserverProxy: config cannot be null.");
+                return;
+            }
+            mExecutor.execute(() -> mObserver.onStarted(config));
+        }
+
+        @Override
+        public void onHotspotStopped() {
+            WifiManager manager = mWifiManager.get();
+            if (manager == null) return;
+
+            mExecutor.execute(() -> mObserver.onStopped());
+        }
+
+        @Override
+        public void onHotspotFailed(int reason) {
+            // do nothing
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index e595164..8f3635f 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,8 +20,8 @@
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telephony.TelephonyManager.NetworkType;
 
+import android.telephony.Annotation.NetworkType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 2e82f4e..4ca2a16 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -23,6 +23,7 @@
 import android.net.Network;
 import android.net.wifi.IActionListener;
 import android.net.wifi.IDppCallback;
+import android.net.wifi.ILocalOnlyHotspotCallback;
 import android.net.wifi.INetworkRequestMatchCallback;
 import android.net.wifi.IOnWifiUsabilityStatsListener;
 import android.net.wifi.ISoftApCallback;
@@ -205,11 +206,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @removed */
-    public void setCountryCode(String country) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public String getCountryCode() {
         throw new UnsupportedOperationException();
@@ -285,22 +281,34 @@
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated replaced by {@link #startLocalOnlyHotspot(ILocalOnlyHotspotCallback, String)} */
+    @Deprecated
     public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
         throw new UnsupportedOperationException();
     }
 
     @Override
+    public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void stopLocalOnlyHotspot() {
         throw new UnsupportedOperationException();
     }
 
-    @Override
+    /** @deprecated replaced by {@link #startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback)} */
+    @Deprecated
     public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
         throw new UnsupportedOperationException();
     }
 
     @Override
+    public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void stopWatchLocalOnlyHotspot() {
         throw new UnsupportedOperationException();
     }
@@ -325,11 +333,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @removed */
-    public Messenger getWifiServiceMessenger(String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public void enableTdls(String remoteIPAddress, boolean enable) {
         throw new UnsupportedOperationException();
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index ba9fc78..6d7e621 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -19,7 +19,6 @@
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.net.MacAddress;
@@ -62,7 +61,8 @@
         config.updateIdentifier = "1234";
         config.fromWifiNetworkSpecifier = true;
         config.fromWifiNetworkSuggestion = true;
-        MacAddress macBeforeParcel = config.getOrCreateRandomizedMacAddress();
+        config.setRandomizedMacAddress(MacAddress.createRandomUnicastAddress());
+        MacAddress macBeforeParcel = config.getRandomizedMacAddress();
         Parcel parcelW = Parcel.obtain();
         config.writeToParcel(parcelW, 0);
         byte[] bytes = parcelW.marshall();
@@ -75,7 +75,7 @@
 
         // lacking a useful config.equals, check two fields near the end.
         assertEquals(cookie, reconfig.getMoTree());
-        assertEquals(macBeforeParcel, reconfig.getOrCreateRandomizedMacAddress());
+        assertEquals(macBeforeParcel, reconfig.getRandomizedMacAddress());
         assertEquals(config.updateIdentifier, reconfig.updateIdentifier);
         assertFalse(reconfig.trusted);
         assertTrue(config.fromWifiNetworkSpecifier);
@@ -193,19 +193,6 @@
     }
 
     @Test
-    public void testGetOrCreateRandomizedMacAddress_SavesAndReturnsSameAddress() {
-        WifiConfiguration config = new WifiConfiguration();
-        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
-        assertEquals(defaultMac, config.getRandomizedMacAddress());
-
-        MacAddress firstMacAddress = config.getOrCreateRandomizedMacAddress();
-        MacAddress secondMacAddress = config.getOrCreateRandomizedMacAddress();
-
-        assertNotEquals(defaultMac, firstMacAddress);
-        assertEquals(firstMacAddress, secondMacAddress);
-    }
-
-    @Test
     public void testSetRandomizedMacAddress_ChangesSavedAddress() {
         WifiConfiguration config = new WifiConfiguration();
         MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
@@ -219,36 +206,6 @@
     }
 
     @Test
-    public void testGetOrCreateRandomizedMacAddress_ReRandomizesInvalidAddress() {
-        WifiConfiguration config =  new WifiConfiguration();
-
-        MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
-        MacAddress macAddressZeroes = MacAddress.ALL_ZEROS_ADDRESS;
-        MacAddress macAddressMulticast = MacAddress.fromString("03:ff:ff:ff:ff:ff");
-        MacAddress macAddressGlobal = MacAddress.fromString("fc:ff:ff:ff:ff:ff");
-
-        config.setRandomizedMacAddress(null);
-        MacAddress macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertNotEquals(macAfterChange, null);
-
-        config.setRandomizedMacAddress(defaultMac);
-        macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertNotEquals(macAfterChange, defaultMac);
-
-        config.setRandomizedMacAddress(macAddressZeroes);
-        macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertNotEquals(macAfterChange, macAddressZeroes);
-
-        config.setRandomizedMacAddress(macAddressMulticast);
-        macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertNotEquals(macAfterChange, macAddressMulticast);
-
-        config.setRandomizedMacAddress(macAddressGlobal);
-        macAfterChange = config.getOrCreateRandomizedMacAddress();
-        assertNotEquals(macAfterChange, macAddressGlobal);
-    }
-
-    @Test
     public void testSetRandomizedMacAddress_DoesNothingWhenNull() {
         WifiConfiguration config = new WifiConfiguration();
         MacAddress defaultMac = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS);
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 7e7f002..885139b 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -16,9 +16,6 @@
 
 package android.net.wifi;
 
-import static android.net.wifi.WifiManager.HOTSPOT_FAILED;
-import static android.net.wifi.WifiManager.HOTSPOT_STARTED;
-import static android.net.wifi.WifiManager.HOTSPOT_STOPPED;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
@@ -68,8 +65,6 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
 
@@ -117,8 +112,6 @@
     private Handler mHandler;
     private TestLooper mLooper;
     private WifiManager mWifiManager;
-    private Messenger mWifiServiceMessenger;
-    final ArgumentCaptor<Messenger> mMessengerCaptor = ArgumentCaptor.forClass(Messenger.class);
 
     @Before public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -128,7 +121,6 @@
         when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
         when(mContext.getOpPackageName()).thenReturn(TEST_PACKAGE_NAME);
 
-        mWifiServiceMessenger = new Messenger(mHandler);
         mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper());
         verify(mWifiService).getVerboseLoggingLevel();
     }
@@ -178,7 +170,7 @@
     @Test
     public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
@@ -196,7 +188,7 @@
     public void testLocalOnlyHotspotReservationCallsStopProperlyInTryWithResources()
             throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
@@ -357,7 +349,7 @@
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         verify(mWifiService)
-                .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
     }
 
     /**
@@ -368,7 +360,7 @@
     public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -380,7 +372,7 @@
     public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new IllegalStateException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -390,12 +382,13 @@
     @Test
     public void testCorrectLooperIsUsedForHandler() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
         verify(mContext, never()).getMainLooper();
+        verify(mContext, never()).getMainExecutor();
     }
 
     /**
@@ -406,15 +399,15 @@
     public void testMainLooperIsUsedWhenHandlerNotProvided() throws Exception {
         // record thread from looper.getThread and check ids.
         TestLooper altLooper = new TestLooper();
-        when(mContext.getMainLooper()).thenReturn(altLooper.getLooper());
+        when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, null);
         altLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
         assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
-        verify(mContext).getMainLooper();
+        verify(mContext).getMainExecutor();
     }
 
     /**
@@ -426,18 +419,17 @@
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         TestLooper callbackLooper = new TestLooper();
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
-        when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+                .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(callback.mOnStartedCalled);
         assertEquals(null, callback.mRes);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STARTED;
-        msg.obj = mApConfig;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStarted(mApConfig);
         mLooper.dispatchAll();
         callbackLooper.dispatchAll();
         assertTrue(callback.mOnStartedCalled);
@@ -453,17 +445,17 @@
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         TestLooper callbackLooper = new TestLooper();
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
-        when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+                .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(callback.mOnStartedCalled);
         assertEquals(null, callback.mRes);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STARTED;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStarted(null);
         mLooper.dispatchAll();
         callbackLooper.dispatchAll();
         assertFalse(callback.mOnStartedCalled);
@@ -478,16 +470,16 @@
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         TestLooper callbackLooper = new TestLooper();
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
-        when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+                .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(callback.mOnStoppedCalled);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STOPPED;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStopped();
         mLooper.dispatchAll();
         callbackLooper.dispatchAll();
         assertTrue(callback.mOnStoppedCalled);
@@ -501,17 +493,16 @@
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         TestLooper callbackLooper = new TestLooper();
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
-        when(mWifiService.startLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class), anyString())).thenReturn(REQUEST_REGISTERED);
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString()))
+                .thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
         assertEquals(ERROR_NOT_SET, callback.mFailureReason);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_FAILED;
-        msg.arg1 = ERROR_NO_CHANNEL;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotFailed(ERROR_NO_CHANNEL);
         mLooper.dispatchAll();
         callbackLooper.dispatchAll();
         assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason);
@@ -523,7 +514,7 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
@@ -539,7 +530,7 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(ERROR_TETHERING_DISALLOWED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
@@ -557,7 +548,7 @@
     public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class), anyString());
+                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString());
         try {
             mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         } catch (SecurityException e) {
@@ -577,7 +568,7 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
@@ -593,7 +584,7 @@
     @Test
     public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
@@ -615,7 +606,7 @@
     @Test
     public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
@@ -634,7 +625,7 @@
     @Test
     public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class),
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
                 anyString())).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
@@ -654,7 +645,7 @@
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
 
         mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
-        verify(mWifiService).startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+        verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
     }
 
     /**
@@ -665,7 +656,7 @@
     public void testStartWatchLocalOnlyHotspotThrowsSecurityException() throws Exception {
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
         doThrow(new SecurityException()).when(mWifiService)
-                .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+                .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
         mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
     }
 
@@ -677,7 +668,7 @@
     public void testStartWatchLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
         doThrow(new IllegalStateException()).when(mWifiService)
-                .startWatchLocalOnlyHotspot(any(Messenger.class), any(IBinder.class));
+                .startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
         mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
     }
 
@@ -822,6 +813,7 @@
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), anyInt());
         verify(mContext, never()).getMainLooper();
+        verify(mContext, never()).getMainExecutor();
     }
 
     /**
@@ -834,6 +826,7 @@
         mLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
         verify(mContext, never()).getMainLooper();
+        verify(mContext, never()).getMainExecutor();
     }
 
     /**
@@ -844,13 +837,13 @@
     public void testMainLooperIsUsedWhenHandlerNotProvidedForObserver() throws Exception {
         // record thread from looper.getThread and check ids.
         TestLooper altLooper = new TestLooper();
-        when(mContext.getMainLooper()).thenReturn(altLooper.getLooper());
+        when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
         mWifiManager.watchLocalOnlyHotspot(observer, null);
         altLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
         assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
-        verify(mContext).getMainLooper();
+        verify(mContext).getMainExecutor();
     }
 
     /**
@@ -865,8 +858,7 @@
         assertFalse(observer.mOnRegistered);
         assertEquals(null, observer.mSub);
         mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
-        verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class));
+        verify(mWifiService).startWatchLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class));
         // now trigger the callback
         observerLooper.dispatchAll();
         mLooper.dispatchAll();
@@ -884,16 +876,14 @@
         TestLooper observerLooper = new TestLooper();
         Handler observerHandler = new Handler(observerLooper.getLooper());
         mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
-        verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class));
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
         observerLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(observer.mOnStartedCalled);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STARTED;
-        msg.obj = mApConfig;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStarted(mApConfig);
         mLooper.dispatchAll();
         observerLooper.dispatchAll();
         assertTrue(observer.mOnStartedCalled);
@@ -910,15 +900,14 @@
         TestLooper observerLooper = new TestLooper();
         Handler observerHandler = new Handler(observerLooper.getLooper());
         mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
-        verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class));
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
         observerLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(observer.mOnStartedCalled);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STARTED;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStarted(null);
         mLooper.dispatchAll();
         observerLooper.dispatchAll();
         assertFalse(observer.mOnStartedCalled);
@@ -936,15 +925,14 @@
         TestLooper observerLooper = new TestLooper();
         Handler observerHandler = new Handler(observerLooper.getLooper());
         mWifiManager.watchLocalOnlyHotspot(observer, observerHandler);
-        verify(mWifiService).startWatchLocalOnlyHotspot(mMessengerCaptor.capture(),
-                  any(IBinder.class));
+        ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
+                ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
+        verify(mWifiService).startWatchLocalOnlyHotspot(internalCallback.capture());
         observerLooper.dispatchAll();
         mLooper.dispatchAll();
         assertFalse(observer.mOnStoppedCalled);
         // now trigger the callback
-        Message msg = new Message();
-        msg.what = HOTSPOT_STOPPED;
-        mMessengerCaptor.getValue().send(msg);
+        internalCallback.getValue().onHotspotStopped();
         mLooper.dispatchAll();
         observerLooper.dispatchAll();
         assertTrue(observer.mOnStoppedCalled);
@@ -1173,6 +1161,7 @@
         Handler altHandler = new Handler(altLooper.getLooper());
         mWifiManager.registerTrafficStateCallback(mTrafficStateCallback, altHandler);
         verify(mContext, never()).getMainLooper();
+        verify(mContext, never()).getMainExecutor();
         verify(mWifiService).registerTrafficStateCallback(
                 any(IBinder.class), callbackCaptor.capture(), anyInt());