Merge "Fix ConcurrentModificationException" into rvc-dev
diff --git a/Android.bp b/Android.bp
index b0e0b35..7f4cd84 100644
--- a/Android.bp
+++ b/Android.bp
@@ -722,6 +722,7 @@
     srcs: [
         "core/java/android/annotation/StringDef.java",
         "core/java/android/net/annotations/PolicyDirection.java",
+        "core/java/com/android/internal/util/HexDump.java",
         "core/java/com/android/internal/util/IState.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
diff --git a/Android.mk b/Android.mk
index aea0c95..3b30714 100644
--- a/Android.mk
+++ b/Android.mk
@@ -39,11 +39,6 @@
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
 $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE):apistubs/android/public/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE):apistubs/android/system/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE):apistubs/android/test/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_MODULE_LIB_API_FILE):apistubs/android/module-lib/api/android.txt)
-$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_SERVER_API_FILE):apistubs/android/system-server/api/android.txt)
 
 # sdk.atree needs to copy the whole dir: $(OUT_DOCS)/offline-sdk to the final zip.
 # So keep offline-sdk-timestamp target here, and unzip offline-sdk-docs.zip to
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 12f211d..ccd87335 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -115,6 +115,11 @@
             baseline_file: "api/lint-baseline.txt",
         },
     },
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        dir: "apistubs/android/public/api",
+        dest: "android.txt",
+    },
     jdiff_enabled: true,
 }
 
@@ -156,6 +161,11 @@
             baseline_file: "api/system-lint-baseline.txt",
         },
     },
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        dir: "apistubs/android/system/api",
+        dest: "android.txt",
+    },
     jdiff_enabled: true,
 }
 
@@ -179,6 +189,11 @@
             baseline_file: "api/test-lint-baseline.txt",
         },
     },
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        dir: "apistubs/android/test/api",
+        dest: "android.txt",
+    },
 }
 
 /////////////////////////////////////////////////////////////////////
@@ -214,6 +229,11 @@
             baseline_file: "api/module-lib-lint-baseline.txt",
         },
     },
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        dir: "apistubs/android/module-lib/api",
+        dest: "android.txt",
+    },
 }
 
 
diff --git a/apex/Android.bp b/apex/Android.bp
index cd34f98..e8f6e6b 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -84,6 +84,24 @@
     },
 }
 
+java_defaults {
+    name: "framework-module-stubs-lib-defaults-publicapi",
+    installable: false,
+    sdk_version: "module_current",
+}
+
+java_defaults {
+    name: "framework-module-stubs-lib-defaults-systemapi",
+    installable: false,
+    sdk_version: "module_current",
+}
+
+java_defaults {
+    name: "framework-module-stubs-lib-defaults-module_libs_api",
+    installable: false,
+    sdk_version: "module_current",
+}
+
 // The defaults for module_libs comes in two parts - defaults for API checks
 // and defaults for stub generation. This is because we want the API txt
 // files to *only* include the module_libs_api, but the stubs to include
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
index e5a685f..c8ca44b 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -116,7 +116,7 @@
         return mUserId;
     }
 
-    void addCommitter(@NonNull Committer committer) {
+    void addOrReplaceCommitter(@NonNull Committer committer) {
         synchronized (mMetadataLock) {
             // We need to override the committer data, so first remove any existing
             // committer before adding the new one.
@@ -139,6 +139,12 @@
         }
     }
 
+    void removeCommitter(@NonNull Committer committer) {
+        synchronized (mMetadataLock) {
+            mCommitters.remove(committer);
+        }
+    }
+
     void removeInvalidCommitters(SparseArray<String> packages) {
         synchronized (mMetadataLock) {
             mCommitters.removeIf(committer ->
@@ -154,7 +160,7 @@
         }
     }
 
-    void addLeasee(String callingPackage, int callingUid, int descriptionResId,
+    void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId,
             CharSequence description, long leaseExpiryTimeMillis) {
         synchronized (mMetadataLock) {
             // We need to override the leasee data, so first remove any existing
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
index 65ccb99..e472d05 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -401,7 +401,7 @@
                 throw new LimitExceededException("Total amount of data with an active lease"
                         + " is exceeding the max limit");
             }
-            blobMetadata.addLeasee(callingPackage, callingUid,
+            blobMetadata.addOrReplaceLeasee(callingPackage, callingUid,
                     descriptionResId, description, leaseExpiryTimeMillis);
             if (LOGV) {
                 Slog.v(TAG, "Acquired lease on " + blobHandle
@@ -573,12 +573,16 @@
                     final Committer newCommitter = new Committer(session.getOwnerPackageName(),
                             session.getOwnerUid(), session.getBlobAccessMode());
                     final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
-                    blob.addCommitter(newCommitter);
+                    blob.addOrReplaceCommitter(newCommitter);
                     try {
                         writeBlobsInfoLocked();
                         session.sendCommitCallbackResult(COMMIT_RESULT_SUCCESS);
                     } catch (Exception e) {
-                        blob.addCommitter(existingCommitter);
+                        if (existingCommitter == null) {
+                            blob.removeCommitter(newCommitter);
+                        } else {
+                            blob.addOrReplaceCommitter(existingCommitter);
+                        }
                         session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
                     }
                     getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
@@ -1349,8 +1353,15 @@
 
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
                     "Caller is not allowed to call this; caller=" + Binder.getCallingUid());
-            mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null)
-                    .recycleOnUse());
+            // We post messages back and forth between mHandler thread and mBackgroundHandler
+            // thread while committing a blob. We need to replicate the same pattern here to
+            // ensure pending messages have been handled.
+            mHandler.post(() -> {
+                mBackgroundHandler.post(() -> {
+                    mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null)
+                            .recycleOnUse());
+                });
+            });
         }
 
         @Override
diff --git a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
index 8fbfb1d..d99830dc4 100644
--- a/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/TEST_MAPPING
@@ -7,6 +7,7 @@
       ],
       "options": [
         {"include-filter": "com.android.server.DeviceIdleControllerTest"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
index bc7a7d3..b76c582 100644
--- a/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/deviceidle/TEST_MAPPING
@@ -4,6 +4,7 @@
       "name": "FrameworksMockingServicesTests",
       "options": [
         {"include-filter": "com.android.server.DeviceIdleControllerTest"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
index e2e1180..484fec3 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/job/TEST_MAPPING
@@ -3,6 +3,7 @@
         {
             "name": "CtsJobSchedulerTestCases",
             "options": [
+                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.LargeTest"}
             ]
@@ -11,6 +12,7 @@
             "name": "FrameworksMockingServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
+                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"}
             ]
         },
@@ -18,6 +20,7 @@
             "name": "FrameworksServicesTests",
             "options": [
                 {"include-filter": "com.android.server.job"},
+                {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
                 {"exclude-annotation": "androidx.test.filters.FlakyTest"}
             ]
         }
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
index ba7572a..c5dc51c 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
+++ b/apex/jobscheduler/service/java/com/android/server/usage/TEST_MAPPING
@@ -4,6 +4,7 @@
       "name": "CtsUsageStatsTestCases",
       "options": [
         {"include-filter": "android.app.usage.cts.UsageStatsTest"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     },
@@ -11,6 +12,7 @@
       "name": "FrameworksServicesTests",
       "options": [
         {"include-filter": "com.android.server.usage"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     }
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 821dd9e..99e82e7 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -132,19 +132,19 @@
 java_library {
     name: "framework-media-stubs-publicapi",
     srcs: [":framework-media-stubs-srcs-publicapi"],
-    sdk_version: "current",
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
 }
 
 java_library {
     name: "framework-media-stubs-systemapi",
     srcs: [":framework-media-stubs-srcs-systemapi"],
-    sdk_version: "system_current",
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
 }
 
 java_library {
     name: "framework-media-stubs-module_libs_api",
     srcs: [":framework-media-stubs-srcs-module_libs_api"],
-    sdk_version: "system_current",
+    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
 }
 
 java_library {
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 6d96200..3fefeb5 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -84,20 +84,17 @@
 java_library {
     name: "framework-permission-stubs-publicapi",
     srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
-    sdk_version: "system_current",
-    installable: false,
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
 }
 
 java_library {
     name: "framework-permission-stubs-systemapi",
     srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
-    sdk_version: "system_current",
-    installable: false,
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
 }
 
 java_library {
     name: "framework-permission-stubs-module_libs_api",
     srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
-    sdk_version: "system_current",
-    installable: false,
+    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
 }
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 86f4ab7..707113b 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -86,7 +86,7 @@
 java_library {
     name: "framework-sdkextensions-stubs-publicapi",
     srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
-    sdk_version: "current",
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
@@ -96,7 +96,7 @@
 java_library {
     name: "framework-sdkextensions-stubs-systemapi",
     srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
-    sdk_version: "system_current",
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
@@ -106,7 +106,7 @@
 java_library {
     name: "framework-sdkextensions-stubs-module_libs_api",
     srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
-    sdk_version: "system_current",
+    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 8185bb0..804eb03 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -46,19 +46,11 @@
         "//frameworks/base/apex/statsd:__subpackages__",
     ],
 }
-
-java_defaults {
-    name: "framework-statsd-defaults",
-    sdk_version: "module_current",
-    libs: [ "framework-annotations-lib" ],
-}
-
 java_library {
     name: "framework-statsd",
-    defaults: [
-        "framework-statsd-defaults",
-    ],
     installable: true,
+    sdk_version: "module_current",
+    libs: [ "framework-annotations-lib" ],
 
     srcs: [
         ":framework-statsd-sources",
@@ -129,39 +121,33 @@
 
 java_library {
     name: "framework-statsd-stubs-publicapi",
-    defaults: [
-        "framework-statsd-defaults",
-    ],
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
     srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/statsd", // statsd apex
-    ]
+    ],
 }
 
 java_library {
     name: "framework-statsd-stubs-systemapi",
-    defaults: [
-        "framework-statsd-defaults",
-    ],
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
     srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/statsd", // statsd apex
-    ]
+    ],
 }
 
 java_library {
     name: "framework-statsd-stubs-module_libs_api",
-    defaults: [
-        "framework-statsd-defaults",
-    ],
+    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
     srcs: [ ":framework-statsd-stubs-srcs-module_libs_api" ],
     visibility: [
         "//frameworks/base", // Framework
         "//frameworks/base/apex/statsd", // statsd apex
         "//frameworks/opt/net/wifi/service" // wifi service
-    ]
+    ],
 }
 
 android_test {
diff --git a/api/current.txt b/api/current.txt
index 680b224..aca06fe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9,7 +9,6 @@
     ctor public Manifest.permission();
     field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER";
     field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION";
-    field public static final String ACCESS_CALL_AUDIO = "android.permission.ACCESS_CALL_AUDIO";
     field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES";
     field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION";
     field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
@@ -289,7 +288,6 @@
     field public static final int alignmentMode = 16843642; // 0x101037a
     field public static final int allContactsName = 16843468; // 0x10102cc
     field public static final int allowAudioPlaybackCapture = 16844289; // 0x1010601
-    field public static final int allowAutoRevokePermissionsExemption = 16844309; // 0x1010615
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowEmbedded = 16843765; // 0x10103f5
@@ -329,6 +327,7 @@
     field public static final int autoLink = 16842928; // 0x10100b0
     field public static final int autoMirrored = 16843754; // 0x10103ea
     field public static final int autoRemoveFromRecents = 16843847; // 0x1010447
+    field public static final int autoRevokePermissions = 16844309; // 0x1010615
     field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546
     field public static final int autoSizeMinTextSize = 16844088; // 0x1010538
     field public static final int autoSizePresetSizes = 16844087; // 0x1010537
@@ -1141,7 +1140,6 @@
     field public static final int reqKeyboardType = 16843304; // 0x1010228
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
-    field public static final int requestAutoRevokePermissionsExemption = 16844308; // 0x1010614
     field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
@@ -25341,11 +25339,12 @@
   public final class MediaCodec.QueueRequest {
     method public void queue();
     method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
+    method @NonNull public android.media.MediaCodec.QueueRequest setEncryptedLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @NonNull android.media.MediaCodec.CryptoInfo);
     method @NonNull public android.media.MediaCodec.QueueRequest setFlags(int);
     method @NonNull public android.media.MediaCodec.QueueRequest setFloatParameter(@NonNull String, float);
     method @NonNull public android.media.MediaCodec.QueueRequest setHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
     method @NonNull public android.media.MediaCodec.QueueRequest setIntegerParameter(@NonNull String, int);
-    method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
+    method @NonNull public android.media.MediaCodec.QueueRequest setLinearBlock(@NonNull android.media.MediaCodec.LinearBlock, int, int);
     method @NonNull public android.media.MediaCodec.QueueRequest setLongParameter(@NonNull String, long);
     method @NonNull public android.media.MediaCodec.QueueRequest setPresentationTimeUs(long);
     method @NonNull public android.media.MediaCodec.QueueRequest setStringParameter(@NonNull String, @NonNull String);
@@ -45923,13 +45922,9 @@
     method public void onConference(android.telecom.Connection, android.telecom.Connection);
     method public void onConnectionServiceFocusGained();
     method public void onConnectionServiceFocusLost();
-    method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
-    method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
-    method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
-    method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
     method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -46419,14 +46414,26 @@
     field public static final int BAND_46 = 46; // 0x2e
     field public static final int BAND_47 = 47; // 0x2f
     field public static final int BAND_48 = 48; // 0x30
+    field public static final int BAND_49 = 49; // 0x31
     field public static final int BAND_5 = 5; // 0x5
+    field public static final int BAND_50 = 50; // 0x32
+    field public static final int BAND_51 = 51; // 0x33
+    field public static final int BAND_52 = 52; // 0x34
+    field public static final int BAND_53 = 53; // 0x35
     field public static final int BAND_6 = 6; // 0x6
     field public static final int BAND_65 = 65; // 0x41
     field public static final int BAND_66 = 66; // 0x42
     field public static final int BAND_68 = 68; // 0x44
     field public static final int BAND_7 = 7; // 0x7
     field public static final int BAND_70 = 70; // 0x46
+    field public static final int BAND_71 = 71; // 0x47
+    field public static final int BAND_72 = 72; // 0x48
+    field public static final int BAND_73 = 73; // 0x49
+    field public static final int BAND_74 = 74; // 0x4a
     field public static final int BAND_8 = 8; // 0x8
+    field public static final int BAND_85 = 85; // 0x55
+    field public static final int BAND_87 = 87; // 0x57
+    field public static final int BAND_88 = 88; // 0x58
     field public static final int BAND_9 = 9; // 0x9
   }
 
@@ -46490,7 +46497,13 @@
     field public static final int BAND_83 = 83; // 0x53
     field public static final int BAND_84 = 84; // 0x54
     field public static final int BAND_86 = 86; // 0x56
+    field public static final int BAND_89 = 89; // 0x59
     field public static final int BAND_90 = 90; // 0x5a
+    field public static final int BAND_91 = 91; // 0x5b
+    field public static final int BAND_92 = 92; // 0x5c
+    field public static final int BAND_93 = 93; // 0x5d
+    field public static final int BAND_94 = 94; // 0x5e
+    field public static final int BAND_95 = 95; // 0x5f
   }
 
   public static final class AccessNetworkConstants.UtranBand {
@@ -47778,7 +47791,7 @@
     method public String createAppSpecificSmsToken(android.app.PendingIntent);
     method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
     method public java.util.ArrayList<java.lang.String> divideMessage(String);
-    method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
+    method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
     method @NonNull public android.os.Bundle getCarrierConfigValues();
     method public static android.telephony.SmsManager getDefault();
     method public static int getDefaultSmsSubscriptionId();
@@ -47788,7 +47801,7 @@
     method public int getSubscriptionId();
     method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
     method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
-    method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
+    method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent);
     method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
     method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, long);
     method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String, @Nullable String);
@@ -55753,8 +55766,8 @@
   }
 
   public final class WindowMetrics {
-    ctor public WindowMetrics(@NonNull android.util.Size, @NonNull android.view.WindowInsets);
-    method @NonNull public android.util.Size getSize();
+    ctor public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets);
+    method @NonNull public android.graphics.Rect getBounds();
     method @NonNull public android.view.WindowInsets getWindowInsets();
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index a1fd0db..b9153d9 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -368,7 +368,6 @@
     method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int);
     field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
     field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
-    field public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
     field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
     field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
     field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
@@ -2030,10 +2029,10 @@
   }
 
   public static class PackageInstaller.Session implements java.io.Closeable {
-    method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
+    method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]);
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender);
-    method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams();
-    method public void removeFile(int, @NonNull String);
+    method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams();
+    method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String);
   }
 
   public static class PackageInstaller.SessionInfo implements android.os.Parcelable {
@@ -2054,7 +2053,7 @@
   public static class PackageInstaller.SessionParams implements android.os.Parcelable {
     method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
     method @Deprecated public void setAllowDowngrade(boolean);
-    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
+    method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams);
     method public void setDontKillApp(boolean);
     method public void setEnableRollback(boolean);
     method public void setEnableRollback(boolean, int);
@@ -6061,7 +6060,7 @@
     method public void release();
   }
 
-  public class InvalidPacketException extends java.lang.Exception {
+  public final class InvalidPacketException extends java.lang.Exception {
     ctor public InvalidPacketException(int);
     method public int getError();
     field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
@@ -6255,7 +6254,7 @@
     field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
   }
 
-  public static class NetworkCapabilities.Builder {
+  public static final class NetworkCapabilities.Builder {
     ctor public NetworkCapabilities.Builder();
     ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
     method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 0bd8a19..ba6feed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -535,6 +535,7 @@
     method public void setWindowingMode(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTIVITY_TYPE_ASSISTANT = 4; // 0x4
+    field public static final int ACTIVITY_TYPE_DREAM = 5; // 0x5
     field public static final int ACTIVITY_TYPE_HOME = 2; // 0x2
     field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3
     field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1
@@ -1833,7 +1834,7 @@
     field public static final int TRANSPORT_TEST = 7; // 0x7
   }
 
-  public static class NetworkCapabilities.Builder {
+  public static final class NetworkCapabilities.Builder {
     ctor public NetworkCapabilities.Builder();
     ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
     method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index 59544a9..ca1d598 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -32,8 +32,11 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This class is a command line utility for manipulating content. A client
@@ -72,7 +75,7 @@
             "usage: adb shell content [subcommand] [options]\n"
                     + "\n"
                     + "usage: adb shell content insert --uri <URI> [--user <USER_ID>]"
-                    + " --bind <BINDING> [--bind <BINDING>...]\n"
+                    + " --bind <BINDING> [--bind <BINDING>...] [--extra <BINDING>...]\n"
                     + "  <URI> a content provider URI.\n"
                     + "  <BINDING> binds a typed value to a column and is formatted:\n"
                     + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
@@ -84,7 +87,8 @@
                     + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
                     + " --bind value:s:new_value\n"
                     + "\n"
-                    + "usage: adb shell content update --uri <URI> [--user <USER_ID>] [--where <WHERE>]\n"
+                    + "usage: adb shell content update --uri <URI> [--user <USER_ID>]"
+                    + " [--where <WHERE>] [--extra <BINDING>...]\n"
                     + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
                     + " - see example below).\n"
                     + "  Example:\n"
@@ -93,14 +97,15 @@
                     + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
                     + "\n"
                     + "usage: adb shell content delete --uri <URI> [--user <USER_ID>] --bind <BINDING>"
-                    + " [--bind <BINDING>...] [--where <WHERE>]\n"
+                    + " [--bind <BINDING>...] [--where <WHERE>] [--extra <BINDING>...]\n"
                     + "  Example:\n"
                     + "  # Remove \"new_setting\" secure setting.\n"
                     + "  adb shell content delete --uri content://settings/secure "
                     + "--where \"name=\'new_setting\'\"\n"
                     + "\n"
                     + "usage: adb shell content query --uri <URI> [--user <USER_ID>]"
-                    + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+                    + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]"
+                    + " [--extra <BINDING>...]\n"
                     + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
                     + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
                     + "  <SORT_ORDER> is the order in which rows in the result should be sorted.\n"
@@ -196,6 +201,7 @@
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
             ContentValues values = new ContentValues();
+            Bundle extras = new Bundle();
             for (String argument; (argument = mTokenizer.nextArg()) != null;) {
                 if (ARGUMENT_URI.equals(argument)) {
                     uri = Uri.parse(argumentValueRequired(argument));
@@ -203,6 +209,8 @@
                     userId = Integer.parseInt(argumentValueRequired(argument));
                 } else if (ARGUMENT_BIND.equals(argument)) {
                     parseBindValue(values);
+                } else if (ARGUMENT_EXTRA.equals(argument)) {
+                    parseBindValue(extras);
                 } else {
                     throw new IllegalArgumentException("Unsupported argument: " + argument);
                 }
@@ -215,20 +223,23 @@
                 throw new IllegalArgumentException("Bindings not specified."
                         + " Did you specify --bind argument(s)?");
             }
-            return new InsertCommand(uri, userId, values);
+            return new InsertCommand(uri, userId, values, extras);
         }
 
         private DeleteCommand parseDeleteCommand() {
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
-            String where = null;
+            Bundle extras = new Bundle();
             for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                 if (ARGUMENT_URI.equals(argument)) {
                     uri = Uri.parse(argumentValueRequired(argument));
                 } else if (ARGUMENT_USER.equals(argument)) {
                     userId = Integer.parseInt(argumentValueRequired(argument));
                 } else if (ARGUMENT_WHERE.equals(argument)) {
-                    where = argumentValueRequired(argument);
+                    extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+                            argumentValueRequired(argument));
+                } else if (ARGUMENT_EXTRA.equals(argument)) {
+                    parseBindValue(extras);
                 } else {
                     throw new IllegalArgumentException("Unsupported argument: " + argument);
                 }
@@ -237,23 +248,26 @@
                 throw new IllegalArgumentException("Content provider URI not specified."
                         + " Did you specify --uri argument?");
             }
-            return new DeleteCommand(uri, userId, where);
+            return new DeleteCommand(uri, userId, extras);
         }
 
         private UpdateCommand parseUpdateCommand() {
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
-            String where = null;
             ContentValues values = new ContentValues();
+            Bundle extras = new Bundle();
             for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                 if (ARGUMENT_URI.equals(argument)) {
                     uri = Uri.parse(argumentValueRequired(argument));
                 } else if (ARGUMENT_USER.equals(argument)) {
                     userId = Integer.parseInt(argumentValueRequired(argument));
                 } else if (ARGUMENT_WHERE.equals(argument)) {
-                    where = argumentValueRequired(argument);
+                    extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+                            argumentValueRequired(argument));
                 } else if (ARGUMENT_BIND.equals(argument)) {
                     parseBindValue(values);
+                } else if (ARGUMENT_EXTRA.equals(argument)) {
+                    parseBindValue(extras);
                 } else {
                     throw new IllegalArgumentException("Unsupported argument: " + argument);
                 }
@@ -266,7 +280,7 @@
                 throw new IllegalArgumentException("Bindings not specified."
                         + " Did you specify --bind argument(s)?");
             }
-            return new UpdateCommand(uri, userId, values, where);
+            return new UpdateCommand(uri, userId, values, extras);
         }
 
         public CallCommand parseCallCommand() {
@@ -274,7 +288,7 @@
             int userId = UserHandle.USER_SYSTEM;
             String arg = null;
             Uri uri = null;
-            ContentValues values = new ContentValues();
+            Bundle extras = new Bundle();
             for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                 if (ARGUMENT_URI.equals(argument)) {
                     uri = Uri.parse(argumentValueRequired(argument));
@@ -285,11 +299,10 @@
                 } else if (ARGUMENT_ARG.equals(argument)) {
                     arg = argumentValueRequired(argument);
                 } else if (ARGUMENT_EXTRA.equals(argument)) {
-                    parseBindValue(values);
+                    parseBindValue(extras);
                 } else {
                     throw new IllegalArgumentException("Unsupported argument: " + argument);
                 }
-
             }
             if (uri == null) {
                 throw new IllegalArgumentException("Content provider URI not specified."
@@ -298,7 +311,7 @@
             if (method == null) {
                 throw new IllegalArgumentException("Content provider method not specified.");
             }
-            return new CallCommand(uri, userId, method, arg, values);
+            return new CallCommand(uri, userId, method, arg, extras);
         }
 
         private GetTypeCommand parseGetTypeCommand() {
@@ -363,19 +376,22 @@
             Uri uri = null;
             int userId = UserHandle.USER_SYSTEM;
             String[] projection = null;
-            String sort = null;
-            String where = null;
+            Bundle extras = new Bundle();
             for (String argument; (argument = mTokenizer.nextArg())!= null;) {
                 if (ARGUMENT_URI.equals(argument)) {
                     uri = Uri.parse(argumentValueRequired(argument));
                 } else if (ARGUMENT_USER.equals(argument)) {
                     userId = Integer.parseInt(argumentValueRequired(argument));
                 } else if (ARGUMENT_WHERE.equals(argument)) {
-                    where = argumentValueRequired(argument);
+                    extras.putString(ContentResolver.QUERY_ARG_SQL_SELECTION,
+                            argumentValueRequired(argument));
                 } else if (ARGUMENT_SORT.equals(argument)) {
-                    sort = argumentValueRequired(argument);
+                    extras.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER,
+                            argumentValueRequired(argument));
                 } else if (ARGUMENT_PROJECTION.equals(argument)) {
                     projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+                } else if (ARGUMENT_EXTRA.equals(argument)) {
+                    parseBindValue(extras);
                 } else {
                     throw new IllegalArgumentException("Unsupported argument: " + argument);
                 }
@@ -384,40 +400,76 @@
                 throw new IllegalArgumentException("Content provider URI not specified."
                         + " Did you specify --uri argument?");
             }
-            return new QueryCommand(uri, userId, projection, where, sort);
+            return new QueryCommand(uri, userId, projection, extras);
         }
 
-        private void parseBindValue(ContentValues values) {
+        private List<String> splitWithEscaping(String argument, char splitChar) {
+            final List<String> res = new ArrayList<>();
+            final StringBuilder cur = new StringBuilder();
+            for (int i = 0; i < argument.length(); i++) {
+                char c = argument.charAt(i);
+                if (c == '\\') {
+                    if (++i == argument.length()) {
+                        throw new IllegalArgumentException("Invalid escaping");
+                    } else {
+                        // Skip escaping char and insert next
+                        c = argument.charAt(i);
+                        cur.append(c);
+                    }
+                } else if (c == splitChar) {
+                    // Splitting char means next string
+                    res.add(cur.toString());
+                    cur.setLength(0);
+                } else {
+                    // Copy non-escaping and non-splitting char
+                    cur.append(c);
+                }
+            }
+            res.add(cur.toString());
+            return res;
+        }
+
+        private Pair<String, Object> parseBindValue() {
             String argument = mTokenizer.nextArg();
             if (TextUtils.isEmpty(argument)) {
                 throw new IllegalArgumentException("Binding not well formed: " + argument);
             }
-            final int firstColonIndex = argument.indexOf(COLON);
-            if (firstColonIndex < 0) {
+            final List<String> split = splitWithEscaping(argument, COLON.charAt(0));
+            if (split.size() != 3) {
                 throw new IllegalArgumentException("Binding not well formed: " + argument);
             }
-            final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1);
-            if (secondColonIndex < 0) {
-                throw new IllegalArgumentException("Binding not well formed: " + argument);
-            }
-            String column = argument.substring(0, firstColonIndex);
-            String type = argument.substring(firstColonIndex + 1, secondColonIndex);
-            String value = argument.substring(secondColonIndex + 1);
+            String column = split.get(0);
+            String type = split.get(1);
+            String value = split.get(2);
             if (TYPE_STRING.equals(type)) {
-                values.put(column, value);
+                return Pair.create(column, value);
             } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
-                values.put(column, Boolean.parseBoolean(value));
-            } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
-                values.put(column, Long.parseLong(value));
-            } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
-                values.put(column, Double.parseDouble(value));
+                return Pair.create(column, Boolean.parseBoolean(value));
+            } else if (TYPE_INTEGER.equalsIgnoreCase(type)) {
+                return Pair.create(column, Integer.parseInt(value));
+            } else if (TYPE_LONG.equalsIgnoreCase(type)) {
+                return Pair.create(column, Long.parseLong(value));
+            } else if (TYPE_FLOAT.equalsIgnoreCase(type)) {
+                return Pair.create(column, Float.parseFloat(value));
+            } else if (TYPE_DOUBLE.equalsIgnoreCase(type)) {
+                return Pair.create(column, Double.parseDouble(value));
             } else if (TYPE_NULL.equalsIgnoreCase(type)) {
-                values.putNull(column);
+                return Pair.create(column, null);
             } else {
                 throw new IllegalArgumentException("Unsupported type: " + type);
             }
         }
 
+        private void parseBindValue(ContentValues values) {
+            final Pair<String, Object> columnValue = parseBindValue();
+            values.putObject(columnValue.first, columnValue.second);
+        }
+
+        private void parseBindValue(Bundle extras) {
+            final Pair<String, Object> columnValue = parseBindValue();
+            extras.putObject(columnValue.first, columnValue.second);
+        }
+
         private String argumentValueRequired(String argument) {
             String value = mTokenizer.nextArg();
             if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
@@ -500,60 +552,43 @@
 
     private static class InsertCommand extends Command {
         final ContentValues mContentValues;
+        final Bundle mExtras;
 
-        public InsertCommand(Uri uri, int userId, ContentValues contentValues) {
+        public InsertCommand(Uri uri, int userId, ContentValues contentValues, Bundle extras) {
             super(uri, userId);
             mContentValues = contentValues;
+            mExtras = extras;
         }
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.insert(resolveCallingPackage(), null, mUri, mContentValues, null);
+            provider.insert(resolveCallingPackage(), null, mUri, mContentValues, mExtras);
         }
     }
 
     private static class DeleteCommand extends Command {
-        final String mWhere;
+        final Bundle mExtras;
 
-        public DeleteCommand(Uri uri, int userId, String where) {
+        public DeleteCommand(Uri uri, int userId, Bundle extras) {
             super(uri, userId);
-            mWhere = where;
+            mExtras = extras;
         }
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.delete(resolveCallingPackage(), null, mUri,
-                    ContentResolver.createSqlQueryBundle(mWhere, null));
+            provider.delete(resolveCallingPackage(), null, mUri, mExtras);
         }
     }
 
     private static class CallCommand extends Command {
         final String mMethod, mArg;
-        Bundle mExtras = null;
+        final Bundle mExtras;
 
-        public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) {
+        public CallCommand(Uri uri, int userId, String method, String arg, Bundle extras) {
             super(uri, userId);
             mMethod = method;
             mArg = arg;
-            if (values != null) {
-                mExtras = new Bundle();
-                for (String key : values.keySet()) {
-                    final Object val = values.get(key);
-                    if (val instanceof String) {
-                        mExtras.putString(key, (String) val);
-                    } else if (val instanceof Float) {
-                        mExtras.putFloat(key, (Float) val);
-                    } else if (val instanceof Double) {
-                        mExtras.putDouble(key, (Double) val);
-                    } else if (val instanceof Boolean) {
-                        mExtras.putBoolean(key, (Boolean) val);
-                    } else if (val instanceof Integer) {
-                        mExtras.putInt(key, (Integer) val);
-                    } else if (val instanceof Long) {
-                        mExtras.putLong(key, (Long) val);
-                    }
-                }
-            }
+            mExtras = extras;
         }
 
         @Override
@@ -604,21 +639,20 @@
         }
     }
 
-    private static class QueryCommand extends DeleteCommand {
+    private static class QueryCommand extends Command {
         final String[] mProjection;
-        final String mSortOrder;
+        final Bundle mExtras;
 
-        public QueryCommand(
-                Uri uri, int userId, String[] projection, String where, String sortOrder) {
-            super(uri, userId, where);
+        public QueryCommand(Uri uri, int userId, String[] projection, Bundle extras) {
+            super(uri, userId);
             mProjection = projection;
-            mSortOrder = sortOrder;
+            mExtras = extras;
         }
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
             Cursor cursor = provider.query(resolveCallingPackage(), null, mUri, mProjection,
-                    ContentResolver.createSqlQueryBundle(mWhere, null, mSortOrder), null);
+                    mExtras, null);
             if (cursor == null) {
                 System.out.println("No result found.");
                 return;
@@ -670,18 +704,19 @@
         }
     }
 
-    private static class UpdateCommand extends InsertCommand {
-        final String mWhere;
+    private static class UpdateCommand extends Command {
+        final ContentValues mValues;
+        final Bundle mExtras;
 
-        public UpdateCommand(Uri uri, int userId, ContentValues contentValues, String where) {
-            super(uri, userId, contentValues);
-            mWhere = where;
+        public UpdateCommand(Uri uri, int userId, ContentValues values, Bundle extras) {
+            super(uri, userId);
+            mValues = values;
+            mExtras = extras;
         }
 
         @Override
         public void onExecute(IContentProvider provider) throws Exception {
-            provider.update(resolveCallingPackage(), null, mUri, mContentValues,
-                    ContentResolver.createSqlQueryBundle(mWhere, null));
+            provider.update(resolveCallingPackage(), null, mUri, mValues, mExtras);
         }
     }
 
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 4529dff..45f21ae 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -97,6 +97,7 @@
         "src/stats_log_util.cpp",
         "src/statscompanion_util.cpp",
         "src/statsd_config.proto",
+        "src/statsd_metadata.proto",
         "src/StatsLogProcessor.cpp",
         "src/StatsService.cpp",
         "src/storage/StorageManager.cpp",
@@ -378,55 +379,55 @@
 // statsd micro benchmark
 //#############################
 
-//cc_benchmark {
-//    name: "statsd_benchmark",
-//    defaults: ["statsd_defaults"],
-//
-//    srcs: [
-//        // atom_field_options.proto needs field_options.proto, but that is
-//        // not included in libprotobuf-cpp-lite, so compile it here.
-//        ":libprotobuf-internal-protos",
-//
-//        "benchmark/duration_metric_benchmark.cpp",
-//        "benchmark/filter_value_benchmark.cpp",
-//        "benchmark/get_dimensions_for_condition_benchmark.cpp",
-//        "benchmark/hello_world_benchmark.cpp",
-//        "benchmark/log_event_benchmark.cpp",
-//        "benchmark/main.cpp",
-//        "benchmark/metric_util.cpp",
-//        "benchmark/stats_write_benchmark.cpp",
-//        "src/atom_field_options.proto",
-//        "src/atoms.proto",
-//        "src/stats_log.proto",
-//    ],
-//
-//    proto: {
-//        type: "lite",
-//        include_dirs: ["external/protobuf/src"],
-//    },
-//
-//    cflags: [
-//        "-Wall",
-//        "-Werror",
-//        "-Wno-unused-parameter",
-//        "-Wno-unused-variable",
-//        "-Wno-unused-function",
-//
-//        // Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
-//        "-Wno-varargs",
-//    ],
-//
-//    static_libs: [
-//        "libplatformprotos",
-//    ],
-//
-//    shared_libs: [
-//        "libgtest_prod",
-//        "libprotobuf-cpp-lite",
-//        "libstatslog",
-//        "libstatssocket",
-//    ],
-//}
+cc_benchmark {
+    name: "statsd_benchmark",
+    defaults: ["statsd_defaults"],
+
+    srcs: [
+        // atom_field_options.proto needs field_options.proto, but that is
+        // not included in libprotobuf-cpp-lite, so compile it here.
+        ":libprotobuf-internal-protos",
+
+        "benchmark/duration_metric_benchmark.cpp",
+        "benchmark/filter_value_benchmark.cpp",
+        "benchmark/get_dimensions_for_condition_benchmark.cpp",
+        "benchmark/hello_world_benchmark.cpp",
+        "benchmark/log_event_benchmark.cpp",
+        "benchmark/main.cpp",
+        "benchmark/metric_util.cpp",
+        "benchmark/stats_write_benchmark.cpp",
+        "src/atom_field_options.proto",
+        "src/atoms.proto",
+        "src/stats_log.proto",
+    ],
+
+    proto: {
+        type: "lite",
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+        "-Wno-unused-variable",
+        "-Wno-unused-function",
+
+        // Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
+        "-Wno-varargs",
+    ],
+
+    static_libs: [
+        "libplatformprotos",
+        "libstatssocket_private",
+    ],
+
+    shared_libs: [
+        "libgtest_prod",
+        "libprotobuf-cpp-lite",
+        "libstatslog",
+    ],
+}
 
 // ====  java proto device library (for test only)  ==============================
 java_library {
diff --git a/cmds/statsd/benchmark/duration_metric_benchmark.cpp b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
index 2631009..2d315d9 100644
--- a/cmds/statsd/benchmark/duration_metric_benchmark.cpp
+++ b/cmds/statsd/benchmark/duration_metric_benchmark.cpp
@@ -137,77 +137,74 @@
     int64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-
-    std::vector<AttributionNodeInternal> attributions1 = {
-            CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
-            CreateAttribution(222, "GMSCoreModule2")};
-
-    std::vector<AttributionNodeInternal> attributions2 = {
-            CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
-            CreateAttribution(555, "GMSCoreModule2")};
-
     std::vector<std::unique_ptr<LogEvent>> events;
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 11));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + 40));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 11,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 40, android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 102));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + 450));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 102,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
+                                                   android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 650));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + bucketSizeNs + 100));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 650,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
+                                                   android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + bucketSizeNs + 640));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + bucketSizeNs + 650));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 640,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 650,
+                                                   android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(9999, "")}, "job0", bucketStartTimeNs + 2));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(9999, "")}, "job0",bucketStartTimeNs + 101));
+    vector<int> attributionUids1 = {9999};
+    vector<string> attributionTags1 = {""};
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 2, attributionUids1,
+                                                  attributionTags1, "job0"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
+                                                   attributionTags1, "job0"));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(9999, "")}, "job2", bucketStartTimeNs + 201));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(9999, "")}, "job2",bucketStartTimeNs + 500));
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids1,
+                                                  attributionTags1, "job2"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids1,
+                                                   attributionTags1, "job2"));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(8888, "")}, "job2", bucketStartTimeNs + 600));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(8888, "")}, "job2",bucketStartTimeNs + bucketSizeNs + 850));
+    vector<int> attributionUids2 = {8888};
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
+                                                  attributionTags1, "job2"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
+                                                   attributionUids2, attributionTags1, "job2"));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 600));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(8888, "")}, "job1", bucketStartTimeNs + bucketSizeNs + 900));
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 600,
+                                                  attributionUids2, attributionTags1, "job1"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
+                                                   attributionUids2, attributionTags1, "job1"));
 
-    events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                          bucketStartTimeNs + 10));
-    events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                        bucketStartTimeNs + 50));
+    vector<int> attributionUids3 = {111, 222, 222};
+    vector<string> attributionTags3 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 10, attributionUids3,
+                                          attributionTags3, "ReadEmail"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 50, attributionUids3, attributionTags3,
+                                        "ReadEmail"));
 
-    events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                          bucketStartTimeNs + 200));
-    events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                        bucketStartTimeNs + bucketSizeNs + 300));
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200, attributionUids3,
+                                          attributionTags3, "ReadEmail"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids3,
+                                        attributionTags3, "ReadEmail"));
 
-    events.push_back(CreateSyncStartEvent(attributions1, "ReadDoc",
-                                          bucketStartTimeNs + 400));
-    events.push_back(CreateSyncEndEvent(attributions1, "ReadDoc",
-                                        bucketStartTimeNs + bucketSizeNs - 1));
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids3,
+                                          attributionTags3, "ReadDoc"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids3,
+                                        attributionTags3, "ReadDoc"));
 
-    events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
-                                          bucketStartTimeNs + 401));
-    events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
-                                        bucketStartTimeNs + bucketSizeNs + 700));
-
+    vector<int> attributionUids4 = {333, 222, 555};
+    vector<string> attributionTags4 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 401, attributionUids4,
+                                          attributionTags4, "ReadEmail"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids4,
+                                        attributionTags4, "ReadEmail"));
     sortLogEventsByTimestamp(&events);
 
     while (state.KeepRunning()) {
@@ -230,78 +227,75 @@
     int64_t bucketSizeNs =
             TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
 
-    std::vector<AttributionNodeInternal> attributions1 = {
-            CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1"),
-            CreateAttribution(222, "GMSCoreModule2")};
-
-    std::vector<AttributionNodeInternal> attributions2 = {
-            CreateAttribution(333, "App2"), CreateAttribution(222, "GMSCoreModule1"),
-            CreateAttribution(555, "GMSCoreModule2")};
-
-    std::vector<AttributionNodeInternal> attributions3 = {
-            CreateAttribution(444, "App3"), CreateAttribution(222, "GMSCoreModule1"),
-            CreateAttribution(555, "GMSCoreModule2")};
-
     std::vector<std::unique_ptr<LogEvent>> events;
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 55));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + 120));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 121));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + 450));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 55,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 120,
+                                                   android::view::DISPLAY_STATE_ON));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 121,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 450,
+                                                   android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-                                                   bucketStartTimeNs + 501));
-    events.push_back(CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-                                                   bucketStartTimeNs + bucketSizeNs + 100));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + 501,
+                                                   android::view::DISPLAY_STATE_OFF));
+    events.push_back(CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 100,
+                                                   android::view::DISPLAY_STATE_ON));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(111, "App1")}, "job1", bucketStartTimeNs + 1));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(111, "App1")}, "job1",bucketStartTimeNs + 101));
+    vector<int> attributionUids1 = {111};
+    vector<string> attributionTags1 = {"App1"};
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 1, attributionUids1,
+                                                  attributionTags1, "job1"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 101, attributionUids1,
+                                                   attributionTags1, "job1"));
 
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 201));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(333, "App2")}, "job2",bucketStartTimeNs + 500));
-    events.push_back(CreateStartScheduledJobEvent(
-            {CreateAttribution(333, "App2")}, "job2", bucketStartTimeNs + 600));
-    events.push_back(CreateFinishScheduledJobEvent(
-            {CreateAttribution(333, "App2")}, "job2",
-            bucketStartTimeNs + bucketSizeNs + 850));
+    vector<int> attributionUids2 = {333};
+    vector<string> attributionTags2 = {"App2"};
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 201, attributionUids2,
+                                                  attributionTags2, "job2"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + 500, attributionUids2,
+                                                   attributionTags2, "job2"));
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + 600, attributionUids2,
+                                                  attributionTags2, "job2"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 850,
+                                                   attributionUids2, attributionTags2, "job2"));
 
-    events.push_back(
-        CreateStartScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
-                                     bucketStartTimeNs + bucketSizeNs - 2));
-    events.push_back(
-        CreateFinishScheduledJobEvent({CreateAttribution(444, "App3")}, "job3",
-                                      bucketStartTimeNs + bucketSizeNs + 900));
+    vector<int> attributionUids3 = {444};
+    vector<string> attributionTags3 = {"App3"};
+    events.push_back(CreateStartScheduledJobEvent(bucketStartTimeNs + bucketSizeNs - 2,
+                                                  attributionUids3, attributionTags3, "job3"));
+    events.push_back(CreateFinishScheduledJobEvent(bucketStartTimeNs + bucketSizeNs + 900,
+                                                   attributionUids3, attributionTags3, "job3"));
 
-    events.push_back(CreateSyncStartEvent(attributions1, "ReadEmail",
-                                          bucketStartTimeNs + 50));
-    events.push_back(CreateSyncEndEvent(attributions1, "ReadEmail",
-                                        bucketStartTimeNs + 110));
+    vector<int> attributionUids4 = {111, 222, 222};
+    vector<string> attributionTags4 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids4,
+                                          attributionTags4, "ReadEmail"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 110, attributionUids4, attributionTags4,
+                                        "ReadEmail"));
 
-    events.push_back(CreateSyncStartEvent(attributions2, "ReadEmail",
-                                          bucketStartTimeNs + 300));
-    events.push_back(CreateSyncEndEvent(attributions2, "ReadEmail",
-                                        bucketStartTimeNs + bucketSizeNs + 700));
-    events.push_back(CreateSyncStartEvent(attributions2, "ReadDoc",
-                                          bucketStartTimeNs + 400));
-    events.push_back(CreateSyncEndEvent(attributions2, "ReadDoc",
-                                        bucketStartTimeNs + bucketSizeNs - 1));
+    vector<int> attributionUids5 = {333, 222, 555};
+    vector<string> attributionTags5 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 300, attributionUids5,
+                                          attributionTags5, "ReadEmail"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids5,
+                                        attributionTags5, "ReadEmail"));
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400, attributionUids5,
+                                          attributionTags5, "ReadDoc"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids5,
+                                        attributionTags5, "ReadDoc"));
 
-    events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
-                                          bucketStartTimeNs + 550));
-    events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
-                                        bucketStartTimeNs + 800));
-    events.push_back(CreateSyncStartEvent(attributions3, "ReadDoc",
-                                          bucketStartTimeNs + bucketSizeNs - 1));
-    events.push_back(CreateSyncEndEvent(attributions3, "ReadDoc",
-                                        bucketStartTimeNs + bucketSizeNs + 700));
+    vector<int> attributionUids6 = {444, 222, 555};
+    vector<string> attributionTags6 = {"App3", "GMSCoreModule1", "GMSCoreModule2"};
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 550, attributionUids6,
+                                          attributionTags6, "ReadDoc"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + 800, attributionUids6, attributionTags6,
+                                        "ReadDoc"));
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids6,
+                                          attributionTags6, "ReadDoc"));
+    events.push_back(CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 700, attributionUids6,
+                                        attributionTags6, "ReadDoc"));
     sortLogEventsByTimestamp(&events);
 
     while (state.KeepRunning()) {
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
index cfe477d..28bf21a 100644
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp
@@ -19,6 +19,7 @@
 #include "HashableDimensionKey.h"
 #include "logd/LogEvent.h"
 #include "stats_log_util.h"
+#include "stats_event.h"
 
 namespace android {
 namespace os {
@@ -26,17 +27,31 @@
 
 using std::vector;
 
-static void createLogEventAndMatcher(LogEvent* event, FieldMatcher *field_matcher) {
-    AttributionNodeInternal node;
-    node.set_uid(100);
-    node.set_tag("LOCATION");
+static void createLogEventAndMatcher(LogEvent* event, FieldMatcher* field_matcher) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, 1);
+    AStatsEvent_overwriteTimestamp(statsEvent, 100000);
 
-    std::vector<AttributionNodeInternal> nodes = {node, node};
-    event->write(nodes);
-    event->write(3.2f);
-    event->write("LOCATION");
-    event->write((int64_t)990);
-    event->init();
+    std::vector<int> attributionUids = {100, 100};
+    std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
+
+    vector<const char*> cTags(attributionTags.size());
+    for (int i = 0; i < cTags.size(); i++) {
+        cTags[i] = attributionTags[i].c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(statsEvent,
+                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
+                                      cTags.data(), attributionUids.size());
+    AStatsEvent_writeFloat(statsEvent, 3.2f);
+    AStatsEvent_writeString(statsEvent, "LOCATION");
+    AStatsEvent_writeInt64(statsEvent, 990);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    event->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
 
     field_matcher->set_field(1);
     auto child = field_matcher->add_child();
@@ -46,7 +61,7 @@
 }
 
 static void BM_FilterValue(benchmark::State& state) {
-    LogEvent event(1, 100000);
+    LogEvent event(/*uid=*/0, /*pid=*/0);
     FieldMatcher field_matcher;
     createLogEventAndMatcher(&event, &field_matcher);
 
diff --git a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
index 2a4403e..c7d01cc 100644
--- a/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
+++ b/cmds/statsd/benchmark/get_dimensions_for_condition_benchmark.cpp
@@ -19,6 +19,7 @@
 #include "HashableDimensionKey.h"
 #include "logd/LogEvent.h"
 #include "stats_log_util.h"
+#include "stats_event.h"
 
 namespace android {
 namespace os {
@@ -27,16 +28,30 @@
 using std::vector;
 
 static void createLogEventAndLink(LogEvent* event, Metric2Condition *link) {
-    AttributionNodeInternal node;
-    node.set_uid(100);
-    node.set_tag("LOCATION");
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, 1);
+    AStatsEvent_overwriteTimestamp(statsEvent, 100000);
 
-    std::vector<AttributionNodeInternal> nodes = {node, node};
-    event->write(nodes);
-    event->write(3.2f);
-    event->write("LOCATION");
-    event->write((int64_t)990);
-    event->init();
+    std::vector<int> attributionUids = {100, 100};
+    std::vector<string> attributionTags = {"LOCATION", "LOCATION"};
+
+    vector<const char*> cTags(attributionTags.size());
+    for (int i = 0; i < cTags.size(); i++) {
+        cTags[i] = attributionTags[i].c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(statsEvent,
+                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
+                                      cTags.data(), attributionUids.size());
+    AStatsEvent_writeFloat(statsEvent, 3.2f);
+    AStatsEvent_writeString(statsEvent, "LOCATION");
+    AStatsEvent_writeInt64(statsEvent, 990);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    event->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
 
     link->conditionId = 1;
 
@@ -54,7 +69,7 @@
 
 static void BM_GetDimensionInCondition(benchmark::State& state) {
     Metric2Condition link;
-    LogEvent event(1, 100000);
+    LogEvent event(/*uid=*/0, /*pid=*/0);
     createLogEventAndLink(&event, &link);
 
     while (state.KeepRunning()) {
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index 8b68743..057e00b 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -39,7 +39,8 @@
     uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
     size_t size = createAndParseStatsEvent(msg);
     while (state.KeepRunning()) {
-        benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000, /*pid=*/ 1001));
+        LogEvent event(/*uid=*/ 1000, /*pid=*/ 1001);
+        benchmark::DoNotOptimize(event.parseBuffer(msg, size));
     }
 }
 BENCHMARK(BM_LogEventCreation);
diff --git a/cmds/statsd/benchmark/metric_util.cpp b/cmds/statsd/benchmark/metric_util.cpp
index cca6d52..4bce89f 100644
--- a/cmds/statsd/benchmark/metric_util.cpp
+++ b/cmds/statsd/benchmark/metric_util.cpp
@@ -14,6 +14,8 @@
 
 #include "metric_util.h"
 
+#include "stats_event.h"
+
 namespace android {
 namespace os {
 namespace statsd {
@@ -246,117 +248,112 @@
 }
 
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-    const android::view::DisplayStateEnum state, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs);
-    event->write(state);
-    event->init();
-    return event;
-}
+        uint64_t timestampNs, const android::view::DisplayStateEnum state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, util::SCREEN_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
 
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-    int level, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
-    (event->write(level));
-    event->init();
-    return event;
+    AStatsEvent_writeInt32(statsEvent, state);
+    AStatsEvent_build(statsEvent);
 
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+    return logEvent;
 }
 
 std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
-        const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(android::util::SCHEDULED_JOB_STATE_CHANGED, timestampNs);
-    event->write(attributions);
-    event->write(jobName);
-    event->write(state);
-    event->init();
-    return event;
+        const vector<int>& attributionUids, const vector<string>& attributionTags,
+        const string& jobName, const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, util::SCHEDULED_JOB_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    vector<const char*> cTags(attributionTags.size());
+    for (int i = 0; i < cTags.size(); i++) {
+        cTags[i] = attributionTags[i].c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(statsEvent,
+                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
+                                      cTags.data(), attributionUids.size());
+    AStatsEvent_writeString(statsEvent, jobName.c_str());
+    AStatsEvent_writeInt32(statsEvent, state);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+    return logEvent;
 }
 
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
-    const std::vector<AttributionNodeInternal>& attributions,
-    const string& name, uint64_t timestampNs) {
-    return CreateScheduledJobStateChangedEvent(
-            attributions, name, ScheduledJobStateChanged::STARTED, timestampNs);
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+                                                       const vector<int>& attributionUids,
+                                                       const vector<string>& attributionTags,
+                                                       const string& jobName) {
+    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+                                               ScheduledJobStateChanged::STARTED, timestampNs);
 }
 
 // Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
-    const std::vector<AttributionNodeInternal>& attributions,
-    const string& name, uint64_t timestampNs) {
-    return CreateScheduledJobStateChangedEvent(
-            attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+                                                        const vector<int>& attributionUids,
+                                                        const vector<string>& attributionTags,
+                                                        const string& jobName) {
+    return CreateScheduledJobStateChangedEvent(attributionUids, attributionTags, jobName,
+                                               ScheduledJobStateChanged::FINISHED, timestampNs);
 }
 
-std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        const WakelockStateChanged::State state, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs);
-    event->write(attributions);
-    event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
-    event->write(wakelockName);
-    event->write(state);
-    event->init();
-    return event;
+std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs,
+                                                      const vector<int>& attributionUids,
+                                                      const vector<string>& attributionTags,
+                                                      const string& name,
+                                                      const SyncStateChanged::State state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, util::SYNC_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    vector<const char*> cTags(attributionTags.size());
+    for (int i = 0; i < cTags.size(); i++) {
+        cTags[i] = attributionTags[i].c_str();
+    }
+
+    AStatsEvent_writeAttributionChain(statsEvent,
+                                      reinterpret_cast<const uint32_t*>(attributionUids.data()),
+                                      cTags.data(), attributionUids.size());
+    AStatsEvent_writeString(statsEvent, name.c_str());
+    AStatsEvent_writeInt32(statsEvent, state);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+    return logEvent;
 }
 
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs) {
-    return CreateWakelockStateChangedEvent(
-        attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs);
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
+                                               const vector<int>& attributionUids,
+                                               const vector<string>& attributionTags,
+                                               const string& name) {
+    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+                                       SyncStateChanged::ON);
 }
 
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs) {
-    return CreateWakelockStateChangedEvent(
-        attributions, wakelockName, WakelockStateChanged::RELEASE, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
-    const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(
-        android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
-    event->write(uid);
-    event->write("pkg_name");
-    event->write("class_name");
-    event->write(state);
-    event->init();
-    return event;
-}
-
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
-    return CreateActivityForegroundStateChangedEvent(
-        uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
-    return CreateActivityForegroundStateChangedEvent(
-        uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& name,
-        const SyncStateChanged::State state, uint64_t timestampNs) {
-    auto event = std::make_unique<LogEvent>(android::util::SYNC_STATE_CHANGED, timestampNs);
-    event->write(attributions);
-    event->write(name);
-    event->write(state);
-    event->init();
-    return event;
-}
-
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& name,
-        uint64_t timestampNs) {
-    return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::ON, timestampNs);
-}
-
-std::unique_ptr<LogEvent> CreateSyncEndEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& name,
-        uint64_t timestampNs) {
-    return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::OFF, timestampNs);
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
+                                             const vector<int>& attributionUids,
+                                             const vector<string>& attributionTags,
+                                             const string& name) {
+    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+                                       SyncStateChanged::OFF);
 }
 
 sp<StatsLogProcessor> CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config,
diff --git a/cmds/statsd/benchmark/metric_util.h b/cmds/statsd/benchmark/metric_util.h
index 9b28d60..6199fa9 100644
--- a/cmds/statsd/benchmark/metric_util.h
+++ b/cmds/statsd/benchmark/metric_util.h
@@ -94,55 +94,31 @@
 
 // Create log event for screen state changed.
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-    const android::view::DisplayStateEnum state, uint64_t timestampNs);
-
-// Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-   int level, uint64_t timestampNs);
+        uint64_t timestampNs, const android::view::DisplayStateEnum state);
 
 // Create log event when scheduled job starts.
-std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
-    const std::vector<AttributionNodeInternal>& attributions,
-    const string& name, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(uint64_t timestampNs,
+                                                       const vector<int>& attributionUids,
+                                                       const vector<string>& attributionTags,
+                                                       const string& jobName);
 
 // Create log event when scheduled job finishes.
-std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(
-    const std::vector<AttributionNodeInternal>& attributions,
-    const string& name, uint64_t timestampNs);
-
-// Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
-
-// Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateFinishScheduledJobEvent(uint64_t timestampNs,
+                                                        const vector<int>& attributionUids,
+                                                        const vector<string>& attributionTags,
+                                                        const string& jobName);
 
 // Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& name,
-        uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
+                                               const vector<int>& attributionUids,
+                                               const vector<string>& attributionTags,
+                                               const string& name);
 
 // Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateSyncEndEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& name,
-        uint64_t timestampNs);
-
-// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(
-    const int uid, uint64_t timestampNs);
-
-// Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs);
-
-// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
-    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
+                                             const vector<int>& attributionUids,
+                                             const vector<string>& attributionTags,
+                                             const string& name);
 
 // Helper function to create an AttributionNodeInternal proto.
 AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
@@ -158,4 +134,4 @@
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 40a24dc..afee79d 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -117,4 +117,6 @@
     optional bool allow_from_any_uid = 50003 [default = false];
 
     repeated string module = 50004;
+
+    optional bool truncate_timestamp = 50005 [default = false];
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index b3d534a..979f950 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -94,7 +94,8 @@
                 10 [(module) = "framework", (module) = "statsdtest"];
         LongPartialWakelockStateChanged long_partial_wakelock_state_changed =
                 11 [(module) = "framework"];
-        MobileRadioPowerStateChanged mobile_radio_power_state_changed = 12 [(module) = "framework"];
+        MobileRadioPowerStateChanged mobile_radio_power_state_changed =
+                12 [(module) = "framework", (truncate_timestamp) = true];
         WifiRadioPowerStateChanged wifi_radio_power_state_changed = 13 [(module) = "framework"];
         ActivityManagerSleepStateChanged activity_manager_sleep_state_changed =
                 14 [(module) = "framework"];
@@ -107,7 +108,8 @@
                 20 [(module) = "framework", (module) = "statsdtest"];
         DeviceIdleModeStateChanged device_idle_mode_state_changed = 21 [(module) = "framework"];
         DeviceIdlingModeStateChanged device_idling_mode_state_changed = 22 [(module) = "framework"];
-        AudioStateChanged audio_state_changed = 23 [(module) = "framework"];
+        AudioStateChanged audio_state_changed =
+                23 [(module) = "framework", (truncate_timestamp) = true];
         MediaCodecStateChanged media_codec_state_changed = 24 [(module) = "framework"];
         CameraStateChanged camera_state_changed = 25 [(module) = "framework"];
         FlashlightStateChanged flashlight_state_changed = 26 [(module) = "framework"];
@@ -128,7 +130,8 @@
         WifiLockStateChanged wifi_lock_state_changed = 37 [(module) = "wifi"];
         WifiSignalStrengthChanged wifi_signal_strength_changed = 38 [(module) = "wifi"];
         WifiScanStateChanged wifi_scan_state_changed = 39 [(module) = "wifi"];
-        PhoneSignalStrengthChanged phone_signal_strength_changed = 40 [(module) = "framework"];
+        PhoneSignalStrengthChanged phone_signal_strength_changed =
+                40 [(module) = "framework", (truncate_timestamp) = true];
         SettingChanged setting_changed = 41 [(module) = "framework"];
         ActivityForegroundStateChanged activity_foreground_state_changed =
                 42 [(module) = "framework", (module) = "statsdtest"];
@@ -154,7 +157,8 @@
                 59 [(module) = "framework", (module) = "statsdtest"];
         ForegroundServiceStateChanged foreground_service_state_changed
                 = 60 [(module) = "framework"];
-        CallStateChanged call_state_changed = 61 [(module) = "telecom"];
+        CallStateChanged call_state_changed =
+                61 [(module) = "telecom", (truncate_timestamp) = true];
         KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"];
         KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"];
         KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"];
@@ -420,8 +424,10 @@
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
-        MobileBytesTransfer mobile_bytes_transfer = 10002 [(module) = "framework"];
-        MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg = 10003 [(module) = "framework"];
+        MobileBytesTransfer mobile_bytes_transfer =
+                10002 [(module) = "framework", (truncate_timestamp) = true];
+        MobileBytesTransferByFgBg mobile_bytes_transfer_by_fg_bg =
+                10003 [(module) = "framework", (truncate_timestamp) = true];
         BluetoothBytesTransfer bluetooth_bytes_transfer = 10006 [(module) = "framework"];
         KernelWakelock kernel_wakelock = 10004 [(module) = "framework"];
         SubsystemSleepState subsystem_sleep_state = 10005 [(module) = "statsdtest"];
@@ -504,6 +510,7 @@
         VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
         SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
         SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
+        SettingSnapshot setting_snapshot = 10080 [(module) = "framework"];
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -2746,21 +2753,32 @@
 
 message BackGesture {
     enum BackType {
-          DEFAULT_BACK_TYPE = 0;
-          COMPLETED = 1;
-          COMPLETED_REJECTED = 2; // successful because coming from rejected area
-          INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
-          INCOMPLETE = 4;
+        DEFAULT_BACK_TYPE = 0;
+        COMPLETED = 1;
+        COMPLETED_REJECTED = 2; // successful because coming from rejected area
+        INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area
+        INCOMPLETE = 4;  // Unsuccessful, for reasons other than below.
+        INCOMPLETE_FAR_FROM_EDGE = 5;  // Unsuccessful, far from the edge.
+        INCOMPLETE_MULTI_TOUCH = 6;  // Unsuccessful, multi touch.
+        INCOMPLETE_LONG_PRESS = 7;  // Unsuccessful, long press.
+        INCOMPLETE_VERTICAL_MOVE = 8;  // Unsuccessful, move vertically.
     }
     optional BackType type = 1;
 
-    optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event
+    optional int32 y_coordinate = 2 [deprecated = true]; // y coordinate for ACTION_DOWN event
+    optional int32 start_x = 4;  // X coordinate for ACTION_DOWN event.
+    optional int32 start_y = 5;  // Y coordinate for ACTION_DOWN event.
+    optional int32 end_x = 6;   // X coordinate for ACTION_MOVE event.
+    optional int32 end_y = 7;  // Y coordinate for ACTION_MOVE event.
+    optional int32 left_boundary = 8;  // left edge width + left inset
+    optional int32 right_boundary = 9;  // screen width - (right edge width + right inset)
+
     enum WindowHorizontalLocation {
         DEFAULT_LOCATION = 0;
         LEFT = 1;
         RIGHT = 2;
     }
-    optional WindowHorizontalLocation x_location = 3;
+    optional WindowHorizontalLocation x_location = 3 [deprecated = true];
 }
 
 message ExclusionRectStateChanged {
@@ -8993,3 +9011,37 @@
     // Which of the ranked targets got picked, default starting position 0.
     optional int32 position_picked = 4;
 }
+
+/**
+ * Logs settings provider values.
+ *
+ * Use DeviceConfig.getProperties to get a list Setting key, query the data from content provider,
+ * then write the value to proto.
+ *
+ */
+message SettingSnapshot {
+
+    // Setting key
+    optional string name = 1;
+
+    enum SettingsValueType {
+        NOTASSIGNED = 0;
+        ASSIGNED_BOOL_TYPE = 1;
+        ASSIGNED_INT_TYPE = 2;
+        ASSIGNED_FLOAT_TYPE = 3;
+        ASSIGNED_STRING_TYPE = 4;
+    };
+    // Setting value type
+    optional SettingsValueType type = 2;
+
+    optional bool bool_value = 3;
+
+    optional int32 int_value = 4;
+
+    optional float float_value = 5;
+
+    optional string str_value = 6;
+
+    // Android user index. 0 for primary user, 10, 11 for secondary or profile user
+    optional int32 user_id = 7;
+}
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 6f54ea7..fca48f9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -80,7 +80,7 @@
             mAllMetricProducers, mAllAnomalyTrackers, mAllPeriodicAlarmTrackers,
             mConditionToMetricMap, mTrackerToMetricMap, mTrackerToConditionMap,
             mActivationAtomTrackerToMetricMap, mDeactivationAtomTrackerToMetricMap,
-            mMetricIndexesWithActivation, mNoReportMetricIds);
+            mAlertTrackerMap, mMetricIndexesWithActivation, mNoReportMetricIds);
 
     mHashStringsInReport = config.hash_strings_in_metric_report();
     mVersionStringsInReport = config.version_strings_in_metric_report();
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 6d20822..7500ec9 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -230,6 +230,10 @@
     // Maps deactivation triggering event to MetricProducers.
     std::unordered_map<int, std::vector<int>> mDeactivationAtomTrackerToMetricMap;
 
+    // Maps AlertIds to the index of the corresponding AnomalyTracker stored in mAllAnomalyTrackers.
+    // The map is used in LoadMetadata to more efficiently lookup AnomalyTrackers from an AlertId.
+    std::unordered_map<int64_t, int> mAlertTrackerMap;
+
     std::vector<int> mMetricIndexesWithActivation;
 
     void initLogSourceWhiteList();
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 40a313a..e5fe87a 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -830,10 +830,10 @@
 
 bool initAlerts(const StatsdConfig& config,
                 const unordered_map<int64_t, int>& metricProducerMap,
+                unordered_map<int64_t, int>& alertTrackerMap,
                 const sp<AlarmMonitor>& anomalyAlarmMonitor,
                 vector<sp<MetricProducer>>& allMetricProducers,
                 vector<sp<AnomalyTracker>>& allAnomalyTrackers) {
-    unordered_map<int64_t, int> anomalyTrackerMap;
     for (int i = 0; i < config.alert_size(); i++) {
         const Alert& alert = config.alert(i);
         const auto& itr = metricProducerMap.find(alert.metric_id());
@@ -858,7 +858,7 @@
             // The ALOGW for this invalid alert was already displayed in addAnomalyTracker().
             return false;
         }
-        anomalyTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
+        alertTrackerMap.insert(std::make_pair(alert.id(), allAnomalyTrackers.size()));
         allAnomalyTrackers.push_back(anomalyTracker);
     }
     for (int i = 0; i < config.subscription_size(); ++i) {
@@ -872,8 +872,8 @@
                 (long long)subscription.id());
             return false;
         }
-        const auto& itr = anomalyTrackerMap.find(subscription.rule_id());
-        if (itr == anomalyTrackerMap.end()) {
+        const auto& itr = alertTrackerMap.find(subscription.rule_id());
+        if (itr == alertTrackerMap.end()) {
             ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"",
                 (long long)subscription.id(), (long long)subscription.rule_id());
             return false;
@@ -944,6 +944,7 @@
                       unordered_map<int, std::vector<int>>& trackerToConditionMap,
                       unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
                       unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+                      unordered_map<int64_t, int>& alertTrackerMap,
                       vector<int>& metricsWithActivation,
                       std::set<int64_t>& noReportMetricIds) {
     unordered_map<int64_t, int> logTrackerMap;
@@ -976,8 +977,8 @@
         ALOGE("initMetricProducers failed");
         return false;
     }
-    if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers,
-                    allAnomalyTrackers)) {
+    if (!initAlerts(config, metricProducerMap, alertTrackerMap, anomalyAlarmMonitor,
+                    allMetricProducers, allAnomalyTrackers)) {
         ALOGE("initAlerts failed");
         return false;
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 5ebb232..a8ccc62 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -128,6 +128,7 @@
                       std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
                       unordered_map<int, std::vector<int>>& activationAtomTrackerToMetricMap,
                       unordered_map<int, std::vector<int>>& deactivationAtomTrackerToMetricMap,
+                      std::unordered_map<int64_t, int>& alertTrackerMap,
                       vector<int>& metricsWithActivation,
                       std::set<int64_t>& noReportMetricIds);
 
diff --git a/cmds/statsd/src/statsd_metadata.proto b/cmds/statsd/src/statsd_metadata.proto
new file mode 100644
index 0000000..e00fe336
--- /dev/null
+++ b/cmds/statsd/src/statsd_metadata.proto
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd.metadata;
+
+message ConfigKey {
+  optional int64 config_id = 1;
+  optional int32 uid = 2;
+}
+
+message Field {
+  optional int32 tag = 1;
+  optional int32 field = 2;
+}
+
+message FieldValue {
+  optional Field field = 1;
+  oneof value {
+    int32 value_int = 2;
+    int64 value_long = 3;
+    float value_float = 4;
+    double value_double = 5;
+    string value_str = 6;
+    bytes value_storage = 7;
+  }
+}
+
+message MetricDimensionKey {
+  repeated FieldValue dimension_key_in_what = 1;
+  repeated FieldValue state_values_key = 2;
+}
+
+message AlertMetadata {
+  optional int64 alert_id = 1;
+  // The earliest time the alert can be fired again in wall clock time.
+  optional int32 last_refractory_ends_sec = 2;
+  optional MetricDimensionKey dimension_key = 3;
+}
+
+// All metadata for a config in statsd
+message StatsMetadata {
+  optional ConfigKey config_key = 1;
+  repeated AlertMetadata alert_metadata = 2;
+}
+
+message StatsMetadataList {
+  repeated StatsMetadata stats_metadata = 1;
+}
\ No newline at end of file
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index 71adc57..356e40b 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -40,6 +40,7 @@
 #ifdef __ANDROID__
 
 const ConfigKey kConfigKey(0, 12345);
+const long kAlertId = 3;
 
 const long timeBaseSec = 1000;
 
@@ -85,7 +86,7 @@
     config.add_no_report_metric(3);
 
     auto alert = config.add_alert();
-    alert->set_id(3);
+    alert->set_id(kAlertId);
     alert->set_metric_id(3);
     alert->set_num_buckets(10);
     alert->set_refractory_period_secs(100);
@@ -218,7 +219,7 @@
     metric->mutable_dimensions_in_what()->add_child()->set_field(1);
 
     auto alert = config.add_alert();
-    alert->set_id(103);
+    alert->set_id(kAlertId);
     alert->set_metric_id(3);
     alert->set_num_buckets(10);
     alert->set_refractory_period_secs(100);
@@ -284,6 +285,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
 
@@ -293,10 +295,14 @@
                                  allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                  trackerToMetricMap, trackerToConditionMap,
                                  activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                 metricsWithActivation, noReportMetricIds));
+                                 alertTrackerMap, metricsWithActivation,
+                                 noReportMetricIds));
     EXPECT_EQ(1u, allMetricProducers.size());
     EXPECT_EQ(1u, allAnomalyTrackers.size());
     EXPECT_EQ(1u, noReportMetricIds.size());
+    EXPECT_EQ(1u, alertTrackerMap.size());
+    EXPECT_NE(alertTrackerMap.find(kAlertId), alertTrackerMap.end());
+    EXPECT_EQ(alertTrackerMap.find(kAlertId)->second, 0);
 }
 
 TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
@@ -316,6 +322,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
 
@@ -325,7 +332,8 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
@@ -345,6 +353,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
 
@@ -354,7 +363,8 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestMissingMatchers) {
@@ -374,6 +384,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -382,7 +393,8 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestMissingPredicate) {
@@ -402,6 +414,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
     EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor,
@@ -410,7 +423,7 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation, noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, TestCirclePredicateDependency) {
@@ -430,6 +443,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
 
@@ -439,7 +453,8 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation,
+                                  noReportMetricIds));
 }
 
 TEST(MetricsManagerTest, testAlertWithUnknownMetric) {
@@ -459,6 +474,7 @@
     unordered_map<int, std::vector<int>> trackerToConditionMap;
     unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
     unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+    unordered_map<int64_t, int> alertTrackerMap;
     vector<int> metricsWithActivation;
     std::set<int64_t> noReportMetricIds;
 
@@ -468,7 +484,8 @@
                                   allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
                                   trackerToMetricMap, trackerToConditionMap,
                                   activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
-                                  metricsWithActivation, noReportMetricIds));
+                                  alertTrackerMap, metricsWithActivation,
+                                  noReportMetricIds));
 }
 
 #else
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 0f39efd5..e58bbb7 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -13,14 +13,17 @@
 // limitations under the License.
 
 #include "src/metrics/EventMetricProducer.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <stdio.h>
+
 #include <vector>
 
+#include "metrics_test_helper.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
 using namespace testing;
 using android::sp;
 using std::set;
@@ -35,6 +38,22 @@
 
 const ConfigKey kConfigKey(0, 12345);
 
+namespace {
+void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeString(statsEvent, str.c_str());
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+}  // anonymous namespace
+
 TEST(EventMetricProducerTest, TestNoCondition) {
     int64_t bucketStartTimeNs = 10000000000;
     int64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -43,8 +62,11 @@
     EventMetric metric;
     metric.set_id(1);
 
-    LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
-    LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -54,8 +76,17 @@
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
 
-    // TODO(b/110561136): get the report and check the content after the ProtoOutputStream change
-    // is done eventProducer.onDumpReport();
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(2, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos());
 }
 
 TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
@@ -67,8 +98,11 @@
     metric.set_id(1);
     metric.set_condition(StringToId("SCREEN_ON"));
 
-    LogEvent event1(1, bucketStartTimeNs + 1);
-    LogEvent event2(1, bucketStartTimeNs + 10);
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1);
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10);
 
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
 
@@ -81,51 +115,67 @@
 
     eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
 
-    // TODO: get the report and check the content after the ProtoOutputStream change is done.
-    // eventProducer.onDumpReport();
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(1, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos());
 }
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
-//
-//    int tagId = 1;
-//    int conditionTagId = 2;
-//
-//    EventMetric metric;
-//    metric.set_id(1);
-//    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-//    MetricConditionLink* link = metric.add_links();
-//    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-//    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-//    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-//
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    EXPECT_TRUE(event1.write("111"));
-//    event1.init();
-//    ConditionKey key1;
-//    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-//    LogEvent event2(tagId, bucketStartTimeNs + 10);
-//    EXPECT_TRUE(event2.write("222"));
-//    event2.init();
-//    ConditionKey key2;
-//    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")};
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-//
-//    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-//
-//    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
-//
-//    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-//    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-//
-//    // TODO: get the report and check the content after the ProtoOutputStream change is done.
-//    // eventProducer.onDumpReport();
-//}
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    EventMetric metric;
+    metric.set_id(1);
+    metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
+    MetricConditionLink* link = metric.add_links();
+    link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
+    buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
+    buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111");
+    ConditionKey key1;
+    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+            getMockedDimensionKey(conditionTagId, 2, "111")};
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222");
+    ConditionKey key2;
+    key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+            getMockedDimensionKey(conditionTagId, 2, "222")};
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    // Condition is false for first event.
+    EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
+    // Condition is true for second event.
+    EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+
+    EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+
+    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+    eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+
+    // Check dump report content.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/,
+                               true /*erase data*/, FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_event_metrics());
+    EXPECT_EQ(1, report.event_metrics().data_size());
+    EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 609324e..d372ffd 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -26,6 +26,7 @@
 #include "src/matchers/SimpleLogMatchingTracker.h"
 #include "src/metrics/MetricProducer.h"
 #include "src/stats_log_util.h"
+#include "stats_event.h"
 #include "tests/statsd_test_util.h"
 
 using namespace testing;
@@ -53,6 +54,28 @@
 const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs;
 const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
 
+namespace {
+shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1,
+                                  int32_t value2) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, value1);
+    AStatsEvent_writeString(statsEvent, str1.c_str());
+    AStatsEvent_writeInt32(statsEvent, value2);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+
+    return logEvent;
+}
+}  // anonymous namespace
+
 /*
  * Tests that the first bucket works correctly
  */
@@ -88,769 +111,685 @@
     EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs());
 }
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(false);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(1);
-//    gaugeFieldMatcher->add_child()->set_field(3);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//                event->write(3);
-//                event->write("some value");
-//                event->write(11);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(10);
-//    event->write("some value");
-//    event->write(11);
-//    event->init();
-//    allData.push_back(event);
-//
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(10, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(11, it->mValue.int_value);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms
-//        .front().mFields->begin()->mValue.int_value);
-//
-//    allData.clear();
-//    std::shared_ptr<LogEvent> event2 = std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10);
-//    event2->write(24);
-//    event2->write("some value");
-//    event2->write(25);
-//    event2->init();
-//    allData.push_back(event2);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(24, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(25, it->mValue.int_value);
-//    // One dimension.
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(10L, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(11L, it->mValue.int_value);
-//
-//    gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
-//    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    // One dimension.
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(24L, it->mValue.int_value);
-//    it++;
-//    EXPECT_EQ(INT, it->mValue.getType());
-//    EXPECT_EQ(25L, it->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//
-//    Alert alert;
-//    alert.set_id(101);
-//    alert.set_metric_id(metricId);
-//    alert.set_trigger_if_sum_gt(25);
-//    alert.set_num_buckets(100);
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
-//                                      bucketStartTimeNs, pullerManager);
-//
-//    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-//    EXPECT_TRUE(anomalyTracker != nullptr);
-//
-//    shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//    event1->write(1);
-//    event1->write(10);
-//    event1->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1);
-//    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    // Partial buckets are not sent to anomaly tracker.
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Create an event in the same partial bucket.
-//    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC);
-//    event2->write(1);
-//    event2->write(10);
-//    event2->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2);
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    // Partial buckets are not sent to anomaly tracker.
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
-//    // tracker.
-//    shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC);
-//    event3->write(1);
-//    event3->write(10);
-//    event3->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3);
-//    EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Next event should trigger creation of new bucket.
-//    shared_ptr<LogEvent> event4 =
-//            make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC);
-//    event4->write(1);
-//    event4->write(10);
-//    event4->init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4);
-//    EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard =
-//            new EventMatcherWizard({new SimpleLogMatchingTracker(
-//                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Return(false))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
-//                event->write("some value");
-//                event->write(2);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event->write("some value");
-//    event->write(1);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    allData.clear();
-//    event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-//    event->write("some value");
-//    event->write(3);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    metric.set_split_bucket_for_app_upgrade(false);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event->write("some value");
-//    event->write(1);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//
-//    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
-//    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
-//                         ->second.front()
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//    metric.set_condition(StringToId("SCREEN_ON"));
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//                event->write("some value");
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write("some value");
-//    event->write(110);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
-//                           ->second.back()
-//                           .mGaugeAtoms.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//
-//    gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
-//    gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
-//    EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
-//                            ->second.back()
-//                            .mGaugeAtoms.front()
-//                            .mFields->begin()
-//                            ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
-//    const int conditionTag = 65;
-//    GaugeMetric metric;
-//    metric.set_id(1111111);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//    metric.set_condition(StringToId("APP_DIED"));
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto dim = metric.mutable_dimensions_in_what();
-//    dim->set_field(tagId);
-//    dim->add_child()->set_field(1);
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    EXPECT_CALL(*wizard, query(_, _, _))
-//            .WillRepeatedly(
-//                    Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
-//                              const bool isPartialLink) {
-//                        int pos[] = {1, 0, 0};
-//                        Field f(conditionTag, pos, 0);
-//                        HashableDimensionKey key;
-//                        key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
-//
-//                        return ConditionState::kTrue;
-//                    }));
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//                event->write(1000);
-//                event->write(100);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
-//                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
-//
-//    gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
-//    EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
-//    EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
-//
-//    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//    allData.clear();
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-//    event->write(1000);
-//    event->write(110);
-//    event->init();
-//    allData.push_back(event);
-//    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-//
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(2);
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    Alert alert;
-//    alert.set_id(101);
-//    alert.set_metric_id(metricId);
-//    alert.set_trigger_if_sum_gt(25);
-//    alert.set_num_buckets(2);
-//    const int32_t refPeriodSec = 60;
-//    alert.set_refractory_period_secs(refPeriodSec);
-//    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-//    int tagId = 1;
-//    std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
-//    event1->write("some value");
-//    event1->write(13);
-//    event1->init();
-//
-//    gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    std::shared_ptr<LogEvent> event2 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20);
-//    event2->write("some value");
-//    event2->write(15);
-//    event2->init();
-//
-//    gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
-//
-//    std::shared_ptr<LogEvent> event3 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10);
-//    event3->write("some value");
-//    event3->write(26);
-//    event3->init();
-//
-//    gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
-//                           ->second.front()
-//                           .mFields->begin()
-//                           ->mValue.int_value);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-//    // The event4 does not have the gauge field. Thus the current bucket value is 0.
-//    std::shared_ptr<LogEvent> event4 =
-//            std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
-//    event4->write("some value");
-//    event4->init();
-//    gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
-//}
-//
-//TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.mutable_gauge_fields_filter()->set_include_all(false);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
-//    gaugeFieldMatcher->set_field(tagId);
-//    gaugeFieldMatcher->add_child()->set_field(1);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//                event->write(4);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//                event->write(5);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Return(true));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//
-//    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 10);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
-//                         ->second.back()
-//                         .mGaugeAtoms[0]
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//    EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
-//                         ->second.back()
-//                         .mGaugeAtoms[1]
-//                         .mFields->begin()
-//                         ->mValue.int_value);
-//}
-//
-//TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.mutable_gauge_fields_filter()->set_include_all(true);
-//    metric.set_max_pull_delay_sec(INT_MAX);
-//    auto dimensionMatcher = metric.mutable_dimensions_in_what();
-//    // use field 1 as dimension.
-//    dimensionMatcher->set_field(tagId);
-//    dimensionMatcher->add_child()->set_field(1);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3);
-//                event->write(3);
-//                event->write(4);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
-//                event->write(4);
-//                event->write(5);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20);
-//                event->write(4);
-//                event->write(6);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }))
-//            .WillOnce(Return(true));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    vector<shared_ptr<LogEvent>> allData;
-//
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 10);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
-//    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucketStartTimeNs + 20);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
-//    trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1);
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
-//    auto bucketIt = gaugeProducer.mPastBuckets.begin();
-//    EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-//    EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-//    bucketIt++;
-//    EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
-//    EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
-//    EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
-//    EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
-//}
-//
-///*
-// * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
-// * is smaller than the "min_bucket_size_nanos" specified in the metric config.
-// */
-//TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
-//    GaugeMetric metric;
-//    metric.set_id(metricId);
-//    metric.set_bucket(FIVE_MINUTES);
-//    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
-//    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    UidMap uidMap;
-//    SimpleAtomMatcher atomMatcher;
-//    atomMatcher.set_atom_id(tagId);
-//    sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({
-//        new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-//
-//    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-//    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-//            // Bucket start.
-//            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-//                data->clear();
-//                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
-//                event->write("field1");
-//                event->write(10);
-//                event->init();
-//                data->push_back(event);
-//                return true;
-//            }));
-//
-//    int triggerId = 5;
-//    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      logEventMatcherIndex, eventMatcherWizard,
-//                                      tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
-//                                      pullerManager);
-//
-//    LogEvent trigger(triggerId, bucketStartTimeNs + 3);
-//    trigger.init();
-//    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger);
-//
-//    // Check dump report.
-//    ProtoOutputStream output;
-//    std::set<string> strSet;
-//    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
-//                                true, FAST /* dump_latency */, &strSet, &output);
-//
-//    StatsLogReport report = outputStreamToProto(&output);
-//    EXPECT_TRUE(report.has_gauge_metrics());
-//    EXPECT_EQ(0, report.gauge_metrics().data_size());
-//    EXPECT_EQ(1, report.gauge_metrics().skipped_size());
-//
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
-//              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
-//              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
-//    EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
-//
-//    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
-//    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
-//    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
-//}
+TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(false);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(1);
+    gaugeFieldMatcher->add_child()->set_field(3);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11));
+
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(10, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(11, it->mValue.int_value);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    allData.clear();
+    allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(24, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(25, it->mValue.int_value);
+    // One dimension.
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(10L, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(11L, it->mValue.int_value);
+
+    gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs);
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+    // One dimension.
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin();
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(24L, it->mValue.int_value);
+    it++;
+    EXPECT_EQ(INT, it->mValue.getType());
+    EXPECT_EQ(25L, it->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) {
+    sp<AlarmMonitor> alarmMonitor;
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(25);
+    alert.set_num_buckets(100);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard,
+                                      -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY));
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Create an event in the same partial bucket.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    // Partial buckets are not sent to anomaly tracker.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket and send previous full bucket to anomaly
+    // tracker.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Next event should trigger creation of new bucket.
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Return(false))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, eventUpgradeTimeNs, 2));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    metric.set_split_bucket_for_app_upgrade(false);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+
+    gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum);
+    EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
+                         ->second.front()
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin()
+                           ->second.back()
+                           .mGaugeAtoms.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+
+    gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10);
+    gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10);
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin()
+                            ->second.back()
+                            .mGaugeAtoms.front()
+                            .mFields->begin()
+                            ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
+    const int conditionTag = 65;
+    GaugeMetric metric;
+    metric.set_id(1111111);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+    metric.set_condition(StringToId("APP_DIED"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto dim = metric.mutable_dimensions_in_what();
+    dim->set_field(tagId);
+    dim->add_child()->set_field(1);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    EXPECT_CALL(*wizard, query(_, _, _))
+            .WillRepeatedly(
+                    Invoke([](const int conditionIndex, const ConditionKey& conditionParameters,
+                              const bool isPartialLink) {
+                        int pos[] = {1, 0, 0};
+                        Field f(conditionTag, pos, 0);
+                        HashableDimensionKey key;
+                        key.mutableValues()->emplace_back(f, Value((int32_t)1000000));
+
+                        return ConditionState::kTrue;
+                    }));
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100));
+                return true;
+            }));
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first;
+    EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size());
+    EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
+
+    EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size());
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+}
+
+TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
+    sp<AlarmMonitor> alarmMonitor;
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
+
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(2);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    Alert alert;
+    alert.set_id(101);
+    alert.set_metric_id(metricId);
+    alert.set_trigger_if_sum_gt(25);
+    alert.set_num_buckets(2);
+    const int32_t refPeriodSec = 60;
+    alert.set_refractory_period_secs(refPeriodSec);
+    sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor);
+
+    int tagId = 1;
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    std::shared_ptr<LogEvent> event2 =
+            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15);
+
+    allData.clear();
+    allData.push_back(event2);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec);
+
+    allData.clear();
+    allData.push_back(
+            CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
+                           ->second.front()
+                           .mFields->begin()
+                           ->mValue.int_value);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+    // This event does not have the gauge field. Thus the current bucket value is 0.
+    allData.clear();
+    allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10));
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
+}
+
+TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.mutable_gauge_fields_filter()->set_include_all(false);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields();
+    gaugeFieldMatcher->set_field(tagId);
+    gaugeFieldMatcher->add_child()->set_field(1);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5));
+                return true;
+            }))
+            .WillOnce(Return(true));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms[0]
+                         .mFields->begin()
+                         ->mValue.int_value);
+    EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin()
+                         ->second.back()
+                         .mGaugeAtoms[1]
+                         .mFields->begin()
+                         ->mValue.int_value);
+}
+
+TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.mutable_gauge_fields_filter()->set_include_all(true);
+    metric.set_max_pull_delay_sec(INT_MAX);
+    auto dimensionMatcher = metric.mutable_dimensions_in_what();
+    // use field 1 as dimension.
+    dimensionMatcher->set_field(tagId);
+    dimensionMatcher->add_child()->set_field(1);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5));
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6));
+                return true;
+            }))
+            .WillOnce(Return(true));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size());
+    EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+    EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size());
+    triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size());
+    auto bucketIt = gaugeProducer.mPastBuckets.begin();
+    EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+    EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+    bucketIt++;
+    EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size());
+    EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value);
+    EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value);
+    EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value);
+}
+
+/*
+ * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size
+ * is smaller than the "min_bucket_size_nanos" specified in the metric config.
+ */
+TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
+    GaugeMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(FIVE_MINUTES);
+    metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES);
+    metric.set_min_bucket_size_nanos(10000000000);  // 10 seconds
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Bucket start.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10));
+                return true;
+            }));
+
+    int triggerId = 5;
+    GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
+                                      tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
+    CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3);
+    gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent);
+
+    // Check dump report.
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true,
+                               FAST /* dump_latency */, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_TRUE(report.has_gauge_metrics());
+    EXPECT_EQ(0, report.gauge_metrics().data_size());
+    EXPECT_EQ(1, report.gauge_metrics().skipped_size());
+
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+              report.gauge_metrics().skipped(0).start_bucket_elapsed_millis());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+              report.gauge_metrics().skipped(0).end_bucket_elapsed_millis());
+    EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size());
+
+    auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0);
+    EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
+    EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index ae6769e..c1d4693 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -1582,9 +1582,9 @@
             ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
-    auto it = valueProducer->mCurrentSlicedBucket.begin();
-    auto& interval1 = it->second[0];
-    auto& baseInfo1 =
+    const auto& it = valueProducer->mCurrentSlicedBucket.begin();
+    ValueMetricProducer::Interval& interval1 = it->second[0];
+    ValueMetricProducer::BaseInfo& baseInfo1 =
             valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
     EXPECT_EQ(1, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, baseInfo1.hasBase);
@@ -1611,16 +1611,9 @@
             break;
         }
     }
-    // auto itBase = valueProducer->mCurrentBaseInfo.begin();
-    // for (; itBase != valueProducer->mCurrentBaseInfo.end(); it++) {
-    //     if (itBase != iterBase) {
-    //         break;
-    //     }
-    // }
     EXPECT_TRUE(it2 != it);
-    // EXPECT_TRUE(itBase != iterBase);
-    auto& interval2 = it2->second[0];
-    auto& baseInfo2 =
+    ValueMetricProducer::Interval& interval2 = it2->second[0];
+    ValueMetricProducer::BaseInfo& baseInfo2 =
             valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
     EXPECT_EQ(2, it2->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, baseInfo2.hasBase);
@@ -1647,23 +1640,28 @@
     valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
 
     EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
-    it = valueProducer->mCurrentSlicedBucket.begin();
-    it2 = std::next(valueProducer->mCurrentSlicedBucket.begin());
-    interval1 = it->second[0];
-    interval2 = it2->second[0];
-    baseInfo1 = valueProducer->mCurrentBaseInfo.find(it->first.getDimensionKeyInWhat())->second[0];
-    baseInfo2 = valueProducer->mCurrentBaseInfo.find(it2->first.getDimensionKeyInWhat())->second[0];
+    // Get new references now that entries have been deleted from the map
+    const auto& it3 = valueProducer->mCurrentSlicedBucket.begin();
+    const auto& it4 = std::next(valueProducer->mCurrentSlicedBucket.begin());
+    EXPECT_EQ(it3->second.size(), 1);
+    EXPECT_EQ(it4->second.size(), 1);
+    ValueMetricProducer::Interval& interval3 = it3->second[0];
+    ValueMetricProducer::Interval& interval4 = it4->second[0];
+    ValueMetricProducer::BaseInfo& baseInfo3 =
+            valueProducer->mCurrentBaseInfo.find(it3->first.getDimensionKeyInWhat())->second[0];
+    ValueMetricProducer::BaseInfo& baseInfo4 =
+            valueProducer->mCurrentBaseInfo.find(it4->first.getDimensionKeyInWhat())->second[0];
 
-    EXPECT_EQ(true, baseInfo1.hasBase);
-    EXPECT_EQ(5, baseInfo1.base.long_value);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(5, interval1.value.long_value);
+    EXPECT_EQ(true, baseInfo3.hasBase);
+    EXPECT_EQ(5, baseInfo3.base.long_value);
+    EXPECT_EQ(false, interval3.hasValue);
+    EXPECT_EQ(5, interval3.value.long_value);
     EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 
-    EXPECT_EQ(true, baseInfo2.hasBase);
-    EXPECT_EQ(13, baseInfo2.base.long_value);
-    EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_EQ(8, interval2.value.long_value);
+    EXPECT_EQ(true, baseInfo4.hasBase);
+    EXPECT_EQ(13, baseInfo4.base.long_value);
+    EXPECT_EQ(false, interval4.hasValue);
+    EXPECT_EQ(8, interval4.value.long_value);
 
     EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
 }
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index c7838fc..8c8836b 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -428,7 +428,7 @@
 
     return logEvent;
 }
-//
+
 void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1,
                             int32_t value2) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
@@ -531,6 +531,18 @@
     return logEvent;
 }
 
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
         uint64_t timestampNs, const android::view::DisplayStateEnum state) {
     AStatsEvent* statsEvent = AStatsEvent_obtain();
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 05e1572..7c01755 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -187,6 +187,8 @@
 
 std::shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs);
 
+void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs);
+
 // Create log event for screen state changed.
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
         uint64_t timestampNs, const android::view::DisplayStateEnum state);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bd3fee2d..21b56d3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4974,10 +4974,8 @@
     ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
             int configChanges, boolean getNonConfigInstance, String reason) {
         ActivityClientRecord r = mActivities.get(token);
-        Class<? extends Activity> activityClass = null;
         if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
         if (r != null) {
-            activityClass = r.activity.getClass();
             r.activity.mConfigChangeFlags |= configChanges;
             if (finishing) {
                 r.activity.mFinished = true;
@@ -5030,7 +5028,6 @@
         synchronized (mResourcesManager) {
             mActivities.remove(token);
         }
-        StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
     }
 
@@ -5050,6 +5047,7 @@
         ActivityClientRecord r = performDestroyActivity(token, finishing,
                 configChanges, getNonConfigInstance, reason);
         if (r != null) {
+            Class<? extends Activity> activityClass = r.activity.getClass();
             cleanUpPendingRemoveWindows(r, finishing);
             WindowManager wm = r.activity.getWindowManager();
             View v = r.activity.mDecor;
@@ -5074,14 +5072,14 @@
                 }
                 if (wtoken != null && r.mPendingRemoveWindow == null) {
                     WindowManagerGlobal.getInstance().closeAll(wtoken,
-                            r.activity.getClass().getName(), "Activity");
+                            activityClass.getName(), "Activity");
                 } else if (r.mPendingRemoveWindow != null) {
                     // We're preserving only one window, others should be closed so app views
                     // will be detached before the final tear down. It should be done now because
                     // some components (e.g. WebView) rely on detach callbacks to perform receiver
                     // unregister and other cleanup.
                     WindowManagerGlobal.getInstance().closeAllExceptView(token, v,
-                            r.activity.getClass().getName(), "Activity");
+                            activityClass.getName(), "Activity");
                 }
                 r.activity.mDecor = null;
             }
@@ -5093,18 +5091,23 @@
                 // about leaking windows, because that is a bug, so if they are
                 // using this recreate facility then they get to live with leaks.
                 WindowManagerGlobal.getInstance().closeAll(token,
-                        r.activity.getClass().getName(), "Activity");
+                        activityClass.getName(), "Activity");
             }
 
             // Mocked out contexts won't be participating in the normal
             // process lifecycle, but if we're running with a proper
             // ApplicationContext we need to have it tear down things
             // cleanly.
-            Context c = r.activity.getBaseContext();
-            if (c instanceof ContextImpl) {
-                ((ContextImpl) c).scheduleFinalCleanup(
-                        r.activity.getClass().getName(), "Activity");
+            final ContextImpl impl = ContextImpl.getImpl(r.activity);
+            if (impl != null) {
+                impl.scheduleFinalCleanup(activityClass.getName(), "Activity");
             }
+
+            r.activity = null;
+            r.window = null;
+            r.hideForNow = false;
+            r.nextIdle = null;
+            StrictMode.decrementExpectedActivityCount(activityClass);
         }
         if (finishing) {
             try {
@@ -5334,10 +5337,6 @@
 
         handleDestroyActivity(r.token, false, configChanges, true, reason);
 
-        r.activity = null;
-        r.window = null;
-        r.hideForNow = false;
-        r.nextIdle = null;
         // Merge any pending results and pending intents; don't just replace them
         if (pendingResults != null) {
             if (r.pendingResults == null) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 26db8f3..a5dcefc 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1088,8 +1088,9 @@
     public static final int OP_ACTIVATE_PLATFORM_VPN = AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN;
     /** @hide */
     public static final int OP_LOADER_USAGE_STATS = AppProtoEnums.APP_OP_LOADER_USAGE_STATS;
-    /** @hide Access telephony call audio */
-    public static final int OP_ACCESS_CALL_AUDIO = AppProtoEnums.APP_OP_ACCESS_CALL_AUDIO;
+
+    // App op deprecated/removed.
+    private static final int OP_DEPRECATED_1 = AppProtoEnums.APP_OP_DEPRECATED_1;
 
     /** @hide Auto-revoke app permissions if app is unused for an extended period */
     public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
@@ -1396,9 +1397,6 @@
     @SystemApi
     public static final String OPSTR_MANAGE_EXTERNAL_STORAGE =
             "android:manage_external_storage";
-    /** @hide Access telephony call audio */
-    @SystemApi
-    public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio";
 
     /** @hide Auto-revoke app permissions if app is unused for an extended period */
     @SystemApi
@@ -1498,7 +1496,6 @@
             OP_MANAGE_EXTERNAL_STORAGE,
             OP_INTERACT_ACROSS_PROFILES,
             OP_LOADER_USAGE_STATS,
-            OP_ACCESS_CALL_AUDIO,
             OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
             OP_AUTO_REVOKE_MANAGED_BY_INSTALLER,
     };
@@ -1608,7 +1605,7 @@
             OP_INTERACT_ACROSS_PROFILES,        //INTERACT_ACROSS_PROFILES
             OP_ACTIVATE_PLATFORM_VPN,           // ACTIVATE_PLATFORM_VPN
             OP_LOADER_USAGE_STATS,              // LOADER_USAGE_STATS
-            OP_ACCESS_CALL_AUDIO,               // ACCESS_CALL_AUDIO
+            OP_DEPRECATED_1,                    // deprecated
             OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -1713,7 +1710,7 @@
             OPSTR_INTERACT_ACROSS_PROFILES,
             OPSTR_ACTIVATE_PLATFORM_VPN,
             OPSTR_LOADER_USAGE_STATS,
-            OPSTR_ACCESS_CALL_AUDIO,
+            "", // deprecated
             OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
             OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER,
     };
@@ -1819,7 +1816,7 @@
             "INTERACT_ACROSS_PROFILES",
             "ACTIVATE_PLATFORM_VPN",
             "LOADER_USAGE_STATS",
-            "ACCESS_CALL_AUDIO",
+            "deprecated",
             "AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
             "AUTO_REVOKE_MANAGED_BY_INSTALLER",
     };
@@ -1926,7 +1923,7 @@
             android.Manifest.permission.INTERACT_ACROSS_PROFILES,
             null, // no permission for OP_ACTIVATE_PLATFORM_VPN
             android.Manifest.permission.LOADER_USAGE_STATS,
-            Manifest.permission.ACCESS_CALL_AUDIO,
+            null, // deprecated operation
             null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -2033,7 +2030,7 @@
             null, // INTERACT_ACROSS_PROFILES
             null, // ACTIVATE_PLATFORM_VPN
             null, // LOADER_USAGE_STATS
-            null, // ACCESS_CALL_AUDIO
+            null, // deprecated operation
             null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -2139,7 +2136,7 @@
             null, // INTERACT_ACROSS_PROFILES
             null, // ACTIVATE_PLATFORM_VPN
             null, // LOADER_USAGE_STATS
-            null, // ACCESS_CALL_AUDIO
+            null, // deprecated operation
             null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             null, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -2244,7 +2241,7 @@
             AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES
             AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
             AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
-            AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
+            AppOpsManager.MODE_IGNORED, // deprecated operation
             AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -2353,7 +2350,7 @@
             false, // INTERACT_ACROSS_PROFILES
             false, // ACTIVATE_PLATFORM_VPN
             false, // LOADER_USAGE_STATS
-            false, // ACCESS_CALL_AUDIO
+            false, // deprecated operation
             false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
             false, // AUTO_REVOKE_MANAGED_BY_INSTALLER
     };
@@ -8446,7 +8443,9 @@
 
     /**
      * Pulls current AppOps access report and picks package and op to watch for next access report
-     *
+     * Returns null if no reports were collected since last call. There is no guarantee of report
+     * collection, hence this method should be called periodically even if no report was collected
+     * to pick different package and op to watch.
      * @hide
      */
     @SystemApi
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 61be01f..0ecc003 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -499,9 +499,11 @@
 
     /**
      * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
-     * {@link #getPackageUid}, if an external service was bound with the flag
-     * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here
-     * will be the kernel user identifier of the external service provider.
+     * {@link #getPackageUid}, if an external service has the
+     * {@link android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set
+     * to <code>true<code> and was bound with the flag
+     * {@link android.content.Context#BIND_EXTERNAL_SERVICE} - in this case, this field here will
+     * be the kernel user identifier of the external service provider.
      */
     public int getDefiningUid() {
         return mDefiningUid;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9ccfe8d..17fd4ef 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2414,8 +2414,7 @@
                 : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
         final List<ResourcesLoader> loaders = mResources.getLoaders();
 
-        // TODO(b/128338354): Rename to createTokenResources
-        return mResourcesManager.createBaseActivityResources(mToken, resDir, splitResDirs,
+        return mResourcesManager.createBaseTokenResources(mToken, resDir, splitResDirs,
                 overlayDirs, libDirs, displayId, null /* overrideConfig */,
                 compatInfo, mClassLoader, loaders);
     }
@@ -2684,7 +2683,7 @@
 
         // Create the base resources for which all configuration contexts for this Activity
         // will be rebased upon.
-        context.setResources(resourcesManager.createBaseActivityResources(activityToken,
+        context.setResources(resourcesManager.createBaseTokenResources(activityToken,
                 packageInfo.getResDir(),
                 splitDirs,
                 packageInfo.getOverlayDirs(),
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index b8221b4..833bfed 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -99,6 +99,7 @@
     void unregisterUidObserver(in IUidObserver observer);
     boolean isUidActive(int uid, String callingPackage);
     int getUidProcessState(int uid, in String callingPackage);
+    boolean isUidActiveOrForeground(int uid, String callingPackage);
     // =============== End of transactions used on native side as well ============================
 
     // Special low-level communication with activity manager.
@@ -143,9 +144,6 @@
     void attachApplication(in IApplicationThread app, long startSeq);
     List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
     @UnsupportedAppUsage
-    List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
-            int ignoreWindowingMode);
-    @UnsupportedAppUsage
     void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
             int flags, in Bundle options);
     @UnsupportedAppUsage
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 03717ec..8b8ebe8 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -155,8 +155,8 @@
     boolean removeTask(int taskId);
     void removeAllVisibleRecentTasks();
     List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
-    List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType,
-            int ignoreWindowingMode);
+    List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
+            boolean filterOnlyVisibleRecents);
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
     boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
             in Intent resultData);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index f590eb9..78d3581 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,8 +48,6 @@
     void clearData(String pkg, int uid, boolean fromApp);
     void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback);
     void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId);
-    // TODO(b/144152069): Remove this after assessing impact on dogfood.
-    void enqueueTextOrCustomToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId, boolean isCustom);
     void cancelToast(String pkg, IBinder token);
     void finishToken(String pkg, IBinder token);
 
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index d650801..10f7835 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -801,6 +801,11 @@
         makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
 
         String libraryPermittedPath = mDataDir;
+        if (mActivityThread == null) {
+            // In a zygote context where mActivityThread is null we can't access the app data dir
+            // and including this in libraryPermittedPath would cause SELinux denials.
+            libraryPermittedPath = "";
+        }
 
         if (isBundledApp) {
             // For bundled apps, add the base directory of the app (e.g.,
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 5f75603..392c05a 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -695,26 +695,26 @@
     }
 
     /**
-     * Creates base resources for an Activity. Calls to
+     * Creates base resources for a binder token. Calls to
      * {@link #getResources(IBinder, String, String[], String[], String[], int, Configuration,
-     * CompatibilityInfo, ClassLoader, List)} with the same activityToken will have their override
+     * CompatibilityInfo, ClassLoader, List)} with the same binder token will have their override
      * configurations merged with the one specified here.
      *
-     * @param activityToken Represents an Activity.
+     * @param token Represents an {@link Activity} or {@link WindowContext}.
      * @param resDir The base resource path. Can be null (only framework resources will be loaded).
      * @param splitResDirs An array of split resource paths. Can be null.
      * @param overlayDirs An array of overlay paths. Can be null.
      * @param libDirs An array of resource library paths. Can be null.
      * @param displayId The ID of the display for which to create the resources.
      * @param overrideConfig The configuration to apply on top of the base configuration. Can be
-     *                       null. This provides the base override for this Activity.
+     *                       {@code null}. This provides the base override for this token.
      * @param compatInfo The compatibility settings to use. Cannot be null. A default to use is
      *                   {@link CompatibilityInfo#DEFAULT_COMPATIBILITY_INFO}.
      * @param classLoader The class loader to use when inflating Resources. If null, the
      *                    {@link ClassLoader#getSystemClassLoader()} is used.
      * @return a Resources object from which to access resources.
      */
-    public @Nullable Resources createBaseActivityResources(@NonNull IBinder activityToken,
+    public @Nullable Resources createBaseTokenResources(@NonNull IBinder token,
             @Nullable String resDir,
             @Nullable String[] splitResDirs,
             @Nullable String[] overlayDirs,
@@ -739,24 +739,24 @@
             classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
 
             if (DEBUG) {
-                Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+                Slog.d(TAG, "createBaseActivityResources activity=" + token
                         + " with key=" + key);
             }
 
             synchronized (this) {
                 // Force the creation of an ActivityResourcesStruct.
-                getOrCreateActivityResourcesStructLocked(activityToken);
+                getOrCreateActivityResourcesStructLocked(token);
             }
 
             // Update any existing Activity Resources references.
-            updateResourcesForActivity(activityToken, overrideConfig, displayId,
+            updateResourcesForActivity(token, overrideConfig, displayId,
                     false /* movedToDifferentDisplay */);
 
-            cleanupReferences(activityToken);
-            rebaseKeyForActivity(activityToken, key);
+            cleanupReferences(token);
+            rebaseKeyForActivity(token, key);
 
             synchronized (this) {
-                Resources resources = findResourcesForActivityLocked(activityToken, key,
+                Resources resources = findResourcesForActivityLocked(token, key,
                         classLoader);
                 if (resources != null) {
                     return resources;
@@ -764,7 +764,7 @@
             }
 
             // Now request an actual Resources object.
-            return createResources(activityToken, key, classLoader);
+            return createResources(token, key, classLoader);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 5ebcc46..b8ad308 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
@@ -291,7 +292,7 @@
      * @see #startActivity(PendingIntent)
      */
     public void startActivity(@NonNull Intent intent) {
-        final ActivityOptions options = prepareActivityOptions();
+        final ActivityOptions options = prepareActivityOptions(null);
         mContext.startActivity(intent, options.toBundle());
     }
 
@@ -304,7 +305,7 @@
      * @see #startActivity(PendingIntent)
      */
     public void startActivity(@NonNull Intent intent, UserHandle user) {
-        final ActivityOptions options = prepareActivityOptions();
+        final ActivityOptions options = prepareActivityOptions(null);
         mContext.startActivityAsUser(intent, options.toBundle(), user);
     }
 
@@ -316,7 +317,7 @@
      * @see #startActivity(Intent)
      */
     public void startActivity(@NonNull PendingIntent pendingIntent) {
-        final ActivityOptions options = prepareActivityOptions();
+        final ActivityOptions options = prepareActivityOptions(null);
         try {
             pendingIntent.send(null /* context */, 0 /* code */, null /* intent */,
                     null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -337,8 +338,7 @@
      */
     public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent,
             @NonNull ActivityOptions options) {
-
-        options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+        prepareActivityOptions(options);
         try {
             pendingIntent.send(mContext, 0 /* code */, fillInIntent,
                     null /* onFinished */, null /* handler */, null /* requiredPermission */,
@@ -364,21 +364,25 @@
             @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
         LauncherApps service =
                 (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
-        options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+        prepareActivityOptions(options);
         service.startShortcut(shortcut, sourceBounds, options.toBundle());
     }
 
     /**
-     * Check if container is ready to launch and create {@link ActivityOptions} to target the
-     * virtual display.
+     * Check if container is ready to launch and modify {@param options} to target the virtual
+     * display, creating them if necessary.
      */
-    private ActivityOptions prepareActivityOptions() {
+    private ActivityOptions prepareActivityOptions(ActivityOptions options) {
         if (mVirtualDisplay == null) {
             throw new IllegalStateException(
                     "Trying to start activity before ActivityView is ready.");
         }
-        final ActivityOptions options = ActivityOptions.makeBasic();
+        if (options == null) {
+            options = ActivityOptions.makeBasic();
+        }
         options.setLaunchDisplayId(getDisplayId());
+        options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
+        options.setTaskAlwaysOnTop(true);
         return options;
     }
 
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 6b40890..37e07de 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -141,6 +141,8 @@
     public static final int ACTIVITY_TYPE_RECENTS = 3;
     /** Assistant activity type. */
     public static final int ACTIVITY_TYPE_ASSISTANT = 4;
+    /** Dream activity type. */
+    public static final int ACTIVITY_TYPE_DREAM = 5;
 
     /** @hide */
     @IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {
@@ -149,6 +151,7 @@
             ACTIVITY_TYPE_HOME,
             ACTIVITY_TYPE_RECENTS,
             ACTIVITY_TYPE_ASSISTANT,
+            ACTIVITY_TYPE_DREAM,
     })
     public @interface ActivityType {}
 
@@ -746,9 +749,11 @@
      * @hide
      */
     public boolean isAlwaysOnTop() {
-        return mWindowingMode == WINDOWING_MODE_PINNED || (mAlwaysOnTop == ALWAYS_ON_TOP_ON
-                && (mWindowingMode == WINDOWING_MODE_FREEFORM
-                    || mWindowingMode == WINDOWING_MODE_MULTI_WINDOW));
+        if (mWindowingMode == WINDOWING_MODE_PINNED) return true;
+        if (mActivityType == ACTIVITY_TYPE_DREAM) return true;
+        if (mAlwaysOnTop != ALWAYS_ON_TOP_ON) return false;
+        return mWindowingMode == WINDOWING_MODE_FREEFORM
+                    || mWindowingMode == WINDOWING_MODE_MULTI_WINDOW;
     }
 
     /**
@@ -798,7 +803,7 @@
 
     /** @hide */
     public static boolean supportSplitScreenWindowingMode(int activityType) {
-        return activityType != ACTIVITY_TYPE_ASSISTANT;
+        return activityType != ACTIVITY_TYPE_ASSISTANT && activityType != ACTIVITY_TYPE_DREAM;
     }
 
     /** @hide */
@@ -823,6 +828,7 @@
             case ACTIVITY_TYPE_HOME: return "home";
             case ACTIVITY_TYPE_RECENTS: return "recents";
             case ACTIVITY_TYPE_ASSISTANT: return "assistant";
+            case ACTIVITY_TYPE_DREAM: return "dream";
         }
         return String.valueOf(applicationType);
     }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c4458b3..10309a9 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4424,11 +4424,13 @@
      * the current factory reset protection (FRP) policy set previously by
      * {@link #setFactoryResetProtectionPolicy}.
      * <p>
-     * This method can also be called by the FRP management agent on device, in which case,
-     * it can pass {@code null} as the ComponentName.
+     * This method can also be called by the FRP management agent on device or with the permission
+     * {@link android.Manifest.permission#MASTER_CLEAR}, in which case, it can pass {@code null}
+     * as the ComponentName.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with or
-     *              {@code null} if called by the FRP management agent on device.
+     *              {@code null} if called by the FRP management agent on device or with the
+     *              permission {@link android.Manifest.permission#MASTER_CLEAR}.
      * @return The current FRP policy object or {@code null} if no policy is set.
      * @throws SecurityException if {@code admin} is not a device owner, a profile owner of
      *                           an organization-owned device or the FRP management agent.
diff --git a/core/java/android/app/admin/FactoryResetProtectionPolicy.java b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
index 954db04..aa94e81 100644
--- a/core/java/android/app/admin/FactoryResetProtectionPolicy.java
+++ b/core/java/android/app/admin/FactoryResetProtectionPolicy.java
@@ -43,6 +43,12 @@
  * reset protection policy for the device by calling the {@code DevicePolicyManager} method
  * {@link DevicePolicyManager#setFactoryResetProtectionPolicy(ComponentName,
  * FactoryResetProtectionPolicy)}}.
+ * <p>
+ * Normally factory reset protection does not kick in if the device is factory reset via Settings.
+ * This is also the case when a device owner sets factory reset protection policy. However,
+ * when a profile owner of an organization-owned device sets factory reset protection policy that
+ * locks the device to specific accounts, the policy will take effect even if factory reset is
+ * performed from Settings.
  *
  * @see DevicePolicyManager#setFactoryResetProtectionPolicy
  * @see DevicePolicyManager#getFactoryResetProtectionPolicy
@@ -236,4 +242,16 @@
         }
     }
 
+    /**
+     * Returns if the policy will result in factory reset protection being locked to
+     * admin-specified accounts.
+     * <p>
+     * When a device has a non-empty factory reset protection policy, trusted factory reset
+     * via Settings will no longer remove factory reset protection from the device.
+     * @hide
+     */
+    public boolean isNotEmpty() {
+        return !mFactoryResetProtectionAccounts.isEmpty() && mFactoryResetProtectionEnabled;
+    }
+
 }
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index e0674d7..fa62a02 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -379,6 +379,7 @@
     public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
             @ConnectionPolicy int connectionPolicy) {
         if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+        verifyDeviceNotNull(device, "setConnectionPolicy");
         final IBluetoothHearingAid service = getService();
         try {
             if (service != null && isEnabled()
@@ -428,6 +429,7 @@
     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
     public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
         if (VDBG) log("getConnectionPolicy(" + device + ")");
+        verifyDeviceNotNull(device, "getConnectionPolicy");
         final IBluetoothHearingAid service = getService();
         try {
             if (service != null && isEnabled()
@@ -504,6 +506,7 @@
         if (VDBG) {
             log("getHiSyncId(" + device + ")");
         }
+        verifyDeviceNotNull(device, "getConnectionPolicy");
         final IBluetoothHearingAid service = getService();
         try {
             if (service == null) {
@@ -577,6 +580,13 @@
         return false;
     }
 
+    private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
+        if (device == null) {
+            Log.e(TAG, methodName + ": device param is null");
+            throw new IllegalArgumentException("Device cannot be null");
+        }
+    }
+
     private boolean isValidDevice(BluetoothDevice device) {
         if (device == null) return false;
 
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 65eb642..9cf6569 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -47,6 +47,7 @@
 import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.ICancellationSignal;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteCallback;
@@ -303,7 +304,11 @@
         @Override
         public void getTypeAsync(Uri uri, RemoteCallback callback) {
             final Bundle result = new Bundle();
-            result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+            try {
+                result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
+            } catch (Exception e) {
+                putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e);
+            }
             callback.sendResult(result);
         }
 
@@ -585,8 +590,12 @@
         public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
                 RemoteCallback callback) {
             final Bundle result = new Bundle();
-            result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
-                    canonicalize(callingPkg, attributionTag, uri));
+            try {
+                result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
+                        canonicalize(callingPkg, attributionTag, uri));
+            } catch (Exception e) {
+                putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e);
+            }
             callback.sendResult(result);
         }
 
@@ -700,6 +709,22 @@
 
             return AppOpsManager.MODE_ALLOWED;
         }
+
+        private void putExceptionInBundle(Bundle bundle, String key, Exception e) {
+            Parcel parcel = Parcel.obtain();
+            try {
+                try {
+                    parcel.writeException(e);
+                } catch (Exception ex) {
+                    // getType threw an unparcelable exception. Wrap the message into
+                    // a parcelable exception type
+                    parcel.writeException(new IllegalStateException(e.getMessage()));
+                }
+                bundle.putByteArray(key, parcel.marshall());
+            } finally {
+                parcel.recycle();
+            }
+        }
     }
 
     boolean checkUser(int pid, int uid, Context context) {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 7510ce7..59862ae 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -55,6 +55,7 @@
 import android.os.IBinder;
 import android.os.ICancellationSignal;
 import android.os.OperationCanceledException;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -735,6 +736,9 @@
     /** @hide */
     public static final String REMOTE_CALLBACK_RESULT = "result";
 
+    /** @hide */
+    public static final String REMOTE_CALLBACK_ERROR = "error";
+
     /**
      * How long we wait for an attached process to publish its content providers
      * before we decide it must be hung.
@@ -874,6 +878,9 @@
                 final StringResultListener resultListener = new StringResultListener();
                 provider.getTypeAsync(url, new RemoteCallback(resultListener));
                 resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+                if (resultListener.exception != null) {
+                    throw resultListener.exception;
+                }
                 return resultListener.result;
             } catch (RemoteException e) {
                 // Arbitrary and not worth documenting, as Activity
@@ -898,6 +905,9 @@
                     resolveUserId(url),
                     new RemoteCallback(resultListener));
             resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS);
+            if (resultListener.exception != null) {
+                throw resultListener.exception;
+            }
             return resultListener.result;
         } catch (RemoteException e) {
             // We just failed to send a oneway request to the System Server. Nothing to do.
@@ -915,15 +925,41 @@
         @GuardedBy("this")
         public T result;
 
+        @GuardedBy("this")
+        public RuntimeException exception;
+
         @Override
         public void onResult(Bundle result) {
             synchronized (this) {
-                this.result = getResultFromBundle(result);
+                this.exception = getExceptionFromBundle(result);
+                if (this.exception == null) {
+                    this.result = getResultFromBundle(result);
+                }
                 done = true;
                 notifyAll();
             }
         }
 
+        private RuntimeException getExceptionFromBundle(Bundle result) {
+            byte[] bytes = result.getByteArray(REMOTE_CALLBACK_ERROR);
+            if (bytes == null) {
+                return null;
+            }
+
+            Parcel parcel = Parcel.obtain();
+            try {
+                parcel.unmarshall(bytes, 0, bytes.length);
+                parcel.setDataPosition(0);
+                parcel.readException();
+            } catch (RuntimeException ex) {
+                return ex;
+            } finally {
+                parcel.recycle();
+            }
+
+            return null;
+        }
+
         protected abstract T getResultFromBundle(Bundle result);
 
         public void waitForResult(long timeout) {
@@ -1250,6 +1286,9 @@
             provider.canonicalizeAsync(mPackageName, mAttributionTag, url,
                     new RemoteCallback(resultListener));
             resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
+            if (resultListener.exception != null) {
+                throw resultListener.exception;
+            }
             return resultListener.result;
         } catch (RemoteException e) {
             // Arbitrary and not worth documenting, as Activity
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 95385ee..b1d6c83 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -11215,6 +11215,17 @@
                 && hasWebURI();
     }
 
+    private boolean isImageCaptureIntent() {
+        return (MediaStore.ACTION_IMAGE_CAPTURE.equals(mAction)
+                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(mAction)
+                || MediaStore.ACTION_VIDEO_CAPTURE.equals(mAction));
+    }
+
+    /** @hide */
+    public boolean isImplicitImageCaptureIntent() {
+        return mPackage == null && mComponent == null && isImageCaptureIntent();
+    }
+
     /**
      * @hide
      */
@@ -11241,9 +11252,7 @@
                 }
                 putParcelableArrayListExtra(EXTRA_STREAM, newStreams);
             }
-        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
-                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
-                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+        } else if (isImageCaptureIntent()) {
             final Uri output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
             if (output != null) {
                 putExtra(MediaStore.EXTRA_OUTPUT, maybeAddUserId(output, contentUserHint));
@@ -11349,9 +11358,7 @@
                 }
             } catch (ClassCastException e) {
             }
-        } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
-                || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(action)
-                || MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) {
+        } else if (isImageCaptureIntent()) {
             final Uri output;
             try {
                 output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 7d5fca4..b6706011 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -752,6 +752,30 @@
     public @interface ApplicationInfoPrivateFlags {}
 
     /**
+     * Constant corresponding to <code>allowed</code> in the
+     * {@link android.R.attr#autoRevokePermissions} attribute.
+     *
+     * @hide
+     */
+    public static final int AUTO_REVOKE_ALLOWED = 0;
+
+    /**
+     * Constant corresponding to <code>discouraged</code> in the
+     * {@link android.R.attr#autoRevokePermissions} attribute.
+     *
+     * @hide
+     */
+    public static final int AUTO_REVOKE_DISCOURAGED = 1;
+
+    /**
+     * Constant corresponding to <code>disallowed</code> in the
+     * {@link android.R.attr#autoRevokePermissions} attribute.
+     *
+     * @hide
+     */
+    public static final int AUTO_REVOKE_DISALLOWED = 2;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * @hide
      */
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 6ba811e..7578ede 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -487,6 +487,34 @@
         }
     }
 
+    /**
+     * Clears the app-op for {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES} back to
+     * its default value for every package on the device.
+     *
+     * <p>This method can be used to ensure that app-op state is not left around on existing users
+     * for previously-configured profiles.
+     *
+     * <p>If the caller does not have the {@link android.Manifest.permission
+     * #CONFIGURE_INTERACT_ACROSS_PROFILES} permission, then they must have the permissions that
+     * would have been required to call {@link android.app.AppOpsManager#setMode(int, int, String,
+     * int)}, which includes {@link android.Manifest.permission#MANAGE_APP_OPS_MODES}.
+     *
+     * <p>Also requires either {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or {@link
+     * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+     *
+     * @hide
+     */
+    @RequiresPermission(
+            allOf={android.Manifest.permission.CONFIGURE_INTERACT_ACROSS_PROFILES,
+                    android.Manifest.permission.INTERACT_ACROSS_USERS})
+    public void clearInteractAcrossProfilesAppOps() {
+        try {
+            mService.clearInteractAcrossProfilesAppOps();
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     private void verifyCanAccessUser(UserHandle userHandle) {
         if (!getTargetUserProfiles().contains(userHandle)) {
             throw new SecurityException("Not allowed to access " + userHandle);
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 9b0dae2..e2850f1 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -40,4 +40,5 @@
     boolean canConfigureInteractAcrossProfiles(in String packageName);
     boolean canUserAttemptToConfigureInteractAcrossProfiles(in String packageName);
     void resetInteractAcrossProfilesAppOps(in List<String> packageNames);
+    void clearInteractAcrossProfilesAppOps();
 }
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 50bee85..1e0b2e3 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1118,6 +1118,7 @@
          * {@hide}
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public @Nullable DataLoaderParams getDataLoaderParams() {
             try {
                 DataLoaderParamsParcel data = mSession.getDataLoaderParams();
@@ -1157,6 +1158,7 @@
          * {@hide}
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes,
                 @NonNull byte[] metadata, @Nullable byte[] signature) {
             try {
@@ -1180,6 +1182,7 @@
          * {@hide}
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2)
         public void removeFile(@FileLocation int location, @NonNull String name) {
             try {
                 mSession.removeFile(location, name);
@@ -1927,7 +1930,9 @@
          * {@hide}
          */
         @SystemApi
-        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
+        @RequiresPermission(allOf = {
+                Manifest.permission.INSTALL_PACKAGES,
+                Manifest.permission.USE_INSTALLER_V2})
         public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) {
             this.dataLoaderParams = dataLoaderParams;
         }
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 39f2858..4c95532 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -192,9 +192,7 @@
 
     ParsingPackage setAllowNativeHeapPointerTagging(boolean allowNativeHeapPointerTagging);
 
-    ParsingPackage setDontAutoRevokePermissions(boolean dontAutoRevokePermissions);
-
-    ParsingPackage setAllowDontAutoRevokePermissions(boolean allowDontAutoRevokePermissions);
+    ParsingPackage setAutoRevokePermissions(int autoRevokePermissions);
 
     ParsingPackage setPreserveLegacyExternalStorage(boolean preserveLegacyExternalStorage);
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index f2ab60a..079a470 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -30,7 +30,6 @@
 import android.content.pm.FeatureInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageParser;
-import android.content.pm.ProcessInfo;
 import android.content.pm.parsing.component.ParsedActivity;
 import android.content.pm.parsing.component.ParsedAttribution;
 import android.content.pm.parsing.component.ParsedComponent;
@@ -405,8 +404,7 @@
     private boolean hasFragileUserData;
     private boolean cantSaveState;
     private boolean allowNativeHeapPointerTagging;
-    private boolean dontAutoRevokePermissions;
-    private boolean allowDontAutoRevokePermissions;
+    private int autoRevokePermissions;
     private boolean preserveLegacyExternalStorage;
 
     protected int gwpAsanMode;
@@ -1089,8 +1087,7 @@
         dest.writeBoolean(this.hasFragileUserData);
         dest.writeBoolean(this.cantSaveState);
         dest.writeBoolean(this.allowNativeHeapPointerTagging);
-        dest.writeBoolean(this.dontAutoRevokePermissions);
-        dest.writeBoolean(this.allowDontAutoRevokePermissions);
+        dest.writeInt(this.autoRevokePermissions);
         dest.writeBoolean(this.preserveLegacyExternalStorage);
         dest.writeArraySet(this.mimeGroups);
         dest.writeInt(this.gwpAsanMode);
@@ -1249,8 +1246,7 @@
         this.hasFragileUserData = in.readBoolean();
         this.cantSaveState = in.readBoolean();
         this.allowNativeHeapPointerTagging = in.readBoolean();
-        this.dontAutoRevokePermissions = in.readBoolean();
-        this.allowDontAutoRevokePermissions = in.readBoolean();
+        this.autoRevokePermissions = in.readInt();
         this.preserveLegacyExternalStorage = in.readBoolean();
         this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
         this.gwpAsanMode = in.readInt();
@@ -2026,13 +2022,8 @@
     }
 
     @Override
-    public boolean isDontAutoRevokePermmissions() {
-        return dontAutoRevokePermissions;
-    }
-
-    @Override
-    public boolean isAllowDontAutoRevokePermmissions() {
-        return allowDontAutoRevokePermissions;
+    public int getAutoRevokePermissions() {
+        return autoRevokePermissions;
     }
 
     @Override
@@ -2506,14 +2497,8 @@
     }
 
     @Override
-    public ParsingPackageImpl setDontAutoRevokePermissions(boolean value) {
-        dontAutoRevokePermissions = value;
-        return this;
-    }
-
-    @Override
-    public ParsingPackageImpl setAllowDontAutoRevokePermissions(boolean value) {
-        allowDontAutoRevokePermissions = value;
+    public ParsingPackageImpl setAutoRevokePermissions(int value) {
+        autoRevokePermissions = value;
         return this;
     }
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index e700c6a5..687bc23 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -771,11 +771,7 @@
     /** @see ApplicationInfo#PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING */
     boolean isAllowNativeHeapPointerTagging();
 
-    /** @see ApplicationInfo#PRIVATE_FLAG2_DONT_AUTO_REVOKE_PERMISSIONS */
-    boolean isDontAutoRevokePermmissions();
-
-    /** @see ApplicationInfo#PRIVATE_FLAG2_ALLOW_DONT_AUTO_REVOKE_PERMISSIONS */
-    boolean isAllowDontAutoRevokePermmissions();
+    int getAutoRevokePermissions();
 
     boolean hasPreserveLegacyExternalStorage();
 
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 789904a..ec77128 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1829,8 +1829,7 @@
                 .setUseEmbeddedDex(bool(false, R.styleable.AndroidManifestApplication_useEmbeddedDex, sa))
                 .setUsesNonSdkApi(bool(false, R.styleable.AndroidManifestApplication_usesNonSdkApi, sa))
                 .setVmSafeMode(bool(false, R.styleable.AndroidManifestApplication_vmSafeMode, sa))
-                .setDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_requestAutoRevokePermissionsExemption, sa))
-                .setAllowDontAutoRevokePermissions(bool(false, R.styleable.AndroidManifestApplication_allowAutoRevokePermissionsExemption, sa))
+                .setAutoRevokePermissions(anInt(R.styleable.AndroidManifestApplication_autoRevokePermissions, sa))
                 // targetSdkVersion gated
                 .setAllowAudioPlaybackCapture(bool(targetSdk >= Build.VERSION_CODES.Q, R.styleable.AndroidManifestApplication_allowAudioPlaybackCapture, sa))
                 .setBaseHardwareAccelerated(bool(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH, R.styleable.AndroidManifestApplication_hardwareAccelerated, sa))
diff --git a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
index 8bcaf82..e7219ca 100644
--- a/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricServiceReceiverInternal.aidl
@@ -26,7 +26,9 @@
 oneway interface IBiometricServiceReceiverInternal {
     // Notify BiometricService that authentication was successful. If user confirmation is required,
     // the auth token must be submitted into KeyStore.
-    void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token);
+    // TODO(b/151967372): Strength should be changed to authenticatorId
+    void onAuthenticationSucceeded(boolean requireConfirmation, in byte[] token,
+            boolean isStrongBiometric);
     // Notify BiometricService authentication was rejected.
     void onAuthenticationFailed();
     // Notify BiometricService than an error has occured. Forward to the correct receiver depending
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java
index c31cb4e..9b3e8c9 100644
--- a/core/java/android/inputmethodservice/InlineSuggestionSession.java
+++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java
@@ -166,9 +166,14 @@
             }
             return;
         }
-
+        // The IME doesn't have information about the virtual view id for the child views in the
+        // web view, so we are only comparing the parent view id here. This means that for cases
+        // where there are two input fields in the web view, they will have the same view id
+        // (although different virtual child id), and we will not be able to distinguish them.
+        final AutofillId imeClientFieldId = mClientAutofillIdSupplier.get();
         if (!mComponentName.getPackageName().equals(mClientPackageNameSupplier.get())
-                || !fieldId.equalsIgnoreSession(mClientAutofillIdSupplier.get())) {
+                || imeClientFieldId == null
+                || fieldId.getViewId() != imeClientFieldId.getViewId()) {
             if (DEBUG) {
                 Log.d(TAG,
                         "handleOnInlineSuggestionsResponse() called on the wrong package/field "
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7c34ddc..782fff2 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -60,7 +60,6 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
-import android.util.Size;
 import android.view.Gravity;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -1249,6 +1248,7 @@
                 WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
         mWindow.getWindow().getAttributes().setFitInsetsTypes(statusBars() | navigationBars());
         mWindow.getWindow().getAttributes().setFitInsetsSides(Side.all() & ~Side.BOTTOM);
+        mWindow.getWindow().getAttributes().setFitInsetsIgnoringVisibility(true);
 
         // IME layout should always be inset by navigation bar, no matter its current visibility,
         // unless automotive requests it, since automotive may hide the navigation bar.
@@ -1479,8 +1479,8 @@
      */
     public int getMaxWidth() {
         final WindowManager windowManager = getSystemService(WindowManager.class);
-        final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
-        return windowSize.getWidth();
+        final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+        return windowBounds.width();
     }
     
     /**
diff --git a/core/java/android/net/InvalidPacketException.java b/core/java/android/net/InvalidPacketException.java
index b3b0f11..1873d77 100644
--- a/core/java/android/net/InvalidPacketException.java
+++ b/core/java/android/net/InvalidPacketException.java
@@ -27,7 +27,7 @@
  * @hide
  */
 @SystemApi
-public class InvalidPacketException extends Exception {
+public final class InvalidPacketException extends Exception {
     private final int mError;
 
     // Must match SocketKeepalive#ERROR_INVALID_IP_ADDRESS.
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index fcfcebd..af9414c 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -415,6 +415,20 @@
             | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
 
     /**
+     * Capabilities that are allowed for test networks. This list must be set so that it is safe
+     * for an unprivileged user to create a network with these capabilities via shell. As such,
+     * it must never contain capabilities that are generally useful to the system, such as
+     * INTERNET, IMS, SUPL, etc.
+     */
+    private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES =
+            (1 << NET_CAPABILITY_NOT_METERED)
+            | (1 << NET_CAPABILITY_NOT_RESTRICTED)
+            | (1 << NET_CAPABILITY_NOT_VPN)
+            | (1 << NET_CAPABILITY_NOT_ROAMING)
+            | (1 << NET_CAPABILITY_NOT_CONGESTED)
+            | (1 << NET_CAPABILITY_NOT_SUSPENDED);
+
+    /**
      * Adds the given capability to this {@code NetworkCapability} instance.
      * Note that when searching for a network to satisfy a request, all capabilities
      * requested must be satisfied.
@@ -646,6 +660,21 @@
     }
 
     /**
+     * Test networks have strong restrictions on what capabilities they can have. Enforce these
+     * restrictions.
+     * @hide
+     */
+    public void restrictCapabilitesForTestNetwork() {
+        final long originalCapabilities = mNetworkCapabilities;
+        final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
+        clearAll();
+        // Reset the transports to only contain TRANSPORT_TEST.
+        mTransportTypes = (1 << TRANSPORT_TEST);
+        mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
+        mNetworkSpecifier = originalSpecifier;
+    }
+
+    /**
      * Representing the transport type.  Apps should generally not care about transport.  A
      * request for a fast internet connection could be satisfied by a number of different
      * transports.  If any are specified here it will be satisfied a Network that matches
@@ -2000,7 +2029,7 @@
      */
     @SystemApi
     @TestApi
-    public static class Builder {
+    public static final class Builder {
         private final NetworkCapabilities mCaps;
 
         /**
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index b7b3c4f..5d2c9d1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -607,6 +607,9 @@
      *                             started.
      * @param pkgDataInfoMap Map from related package names to private data directory
      *                       volume UUID and inode number.
+     * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+     *                       volume UUID and inode number.
+     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
      * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      * @param zygoteArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
@@ -631,13 +634,17 @@
                                            @Nullable long[] disabledCompatChanges,
                                            @Nullable Map<String, Pair<String, Long>>
                                                    pkgDataInfoMap,
+                                           @Nullable Map<String, Pair<String, Long>>
+                                                   whitelistedDataInfoMap,
+                                           boolean bindMountAppsData,
                                            boolean bindMountAppStorageDirs,
                                            @Nullable String[] zygoteArgs) {
         return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
                     zygotePolicyFlags, isTopApp, disabledCompatChanges,
-                    pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+                    pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+                    bindMountAppStorageDirs, zygoteArgs);
     }
 
     /** @hide */
@@ -661,7 +668,8 @@
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
                     /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, /*isTopApp=*/ false,
-                disabledCompatChanges, /* pkgDataInfoMap */ null, false, zygoteArgs);
+                disabledCompatChanges, /* pkgDataInfoMap */ null,
+                /* whitelistedDataInfoMap */ null, false, false, zygoteArgs);
     }
 
     /**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 5f3f14f..a4c99c0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -333,6 +333,9 @@
      *                             started.
      * @param pkgDataInfoMap Map from related package names to private data directory
      *                       volume UUID and inode number.
+     * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+     *                       volume UUID and inode number.
+     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
      * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      *
      * @param zygoteArgs Additional arguments to supply to the Zygote process.
@@ -355,6 +358,9 @@
                                                   @Nullable long[] disabledCompatChanges,
                                                   @Nullable Map<String, Pair<String, Long>>
                                                           pkgDataInfoMap,
+                                                  @Nullable Map<String, Pair<String, Long>>
+                                                          whitelistedDataInfoMap,
+                                                  boolean bindMountAppsData,
                                                   boolean bindMountAppStorageDirs,
                                                   @Nullable String[] zygoteArgs) {
         // TODO (chriswailes): Is there a better place to check this value?
@@ -367,7 +373,8 @@
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
                     packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
-                    pkgDataInfoMap, bindMountAppStorageDirs, zygoteArgs);
+                    pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
+                    bindMountAppStorageDirs, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -608,6 +615,9 @@
      * @param disabledCompatChanges a list of disabled compat changes for the process being started.
      * @param pkgDataInfoMap Map from related package names to private data directory volume UUID
      *                       and inode number.
+     * @param whitelistedDataInfoMap Map from whitelisted package names to private data directory
+     *                       volume UUID and inode number.
+     * @param bindMountAppsData whether zygote needs to mount CE and DE data.
      * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data.
      * @param extraArgs Additional arguments to supply to the zygote process.
      * @return An object that describes the result of the attempt to start the process.
@@ -631,6 +641,9 @@
                                                       @Nullable long[] disabledCompatChanges,
                                                       @Nullable Map<String, Pair<String, Long>>
                                                               pkgDataInfoMap,
+                                                      @Nullable Map<String, Pair<String, Long>>
+                                                              whitelistedDataInfoMap,
+                                                      boolean bindMountAppsData,
                                                       boolean bindMountAppStorageDirs,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
@@ -728,11 +741,33 @@
             }
             argsForZygote.add(sb.toString());
         }
+        if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(Zygote.WHITELISTED_DATA_INFO_MAP);
+            sb.append("=");
+            boolean started = false;
+            for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) {
+                if (started) {
+                    sb.append(',');
+                }
+                started = true;
+                sb.append(entry.getKey());
+                sb.append(',');
+                sb.append(entry.getValue().first);
+                sb.append(',');
+                sb.append(entry.getValue().second);
+            }
+            argsForZygote.add(sb.toString());
+        }
 
         if (bindMountAppStorageDirs) {
             argsForZygote.add(Zygote.BIND_MOUNT_APP_STORAGE_DIRS);
         }
 
+        if (bindMountAppsData) {
+            argsForZygote.add(Zygote.BIND_MOUNT_APP_DATA_DIRS);
+        }
+
         if (disabledCompatChanges != null && disabledCompatChanges.length > 0) {
             StringBuilder sb = new StringBuilder();
             sb.append("--disabled-compat-changes=");
@@ -1291,6 +1326,7 @@
                     true /* startChildZygote */, null /* packageName */,
                     ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */,
                     null /* disabledCompatChanges */, null /* pkgDataInfoMap */,
+                    null /* whitelistedDataInfoMap */, false /* bindMountAppsData*/,
                     /* bindMountAppStorageDirs */ false, extraArgs);
 
         } catch (ZygoteStartFailedEx ex) {
diff --git a/core/java/android/os/incremental/V4Signature.java b/core/java/android/os/incremental/V4Signature.java
index 71f931d..5cc73ca 100644
--- a/core/java/android/os/incremental/V4Signature.java
+++ b/core/java/android/os/incremental/V4Signature.java
@@ -72,16 +72,16 @@
      * V4 signature data.
      */
     public static class SigningInfo {
-        public final byte[] v3Digest;  // used to match with the corresponding APK
+        public final byte[] apkDigest;  // used to match with the corresponding APK
         public final byte[] certificate; // ASN.1 DER form
         public final byte[] additionalData; // a free-form binary data blob
         public final byte[] publicKey; // ASN.1 DER, must match the certificate
         public final int signatureAlgorithmId; // see the APK v2 doc for the list
         public final byte[] signature;
 
-        SigningInfo(byte[] v3Digest, byte[] certificate, byte[] additionalData,
+        SigningInfo(byte[] apkDigest, byte[] certificate, byte[] additionalData,
                 byte[] publicKey, int signatureAlgorithmId, byte[] signature) {
-            this.v3Digest = v3Digest;
+            this.apkDigest = apkDigest;
             this.certificate = certificate;
             this.additionalData = additionalData;
             this.publicKey = publicKey;
@@ -94,13 +94,13 @@
          */
         public static SigningInfo fromByteArray(byte[] bytes) throws IOException {
             ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
-            byte[] v3Digest = readBytes(buffer);
+            byte[] apkDigest = readBytes(buffer);
             byte[] certificate = readBytes(buffer);
             byte[] additionalData = readBytes(buffer);
             byte[] publicKey = readBytes(buffer);
             int signatureAlgorithmId = buffer.getInt();
             byte[] signature = readBytes(buffer);
-            return new SigningInfo(v3Digest, certificate, additionalData, publicKey,
+            return new SigningInfo(apkDigest, certificate, additionalData, publicKey,
                     signatureAlgorithmId, signature);
         }
     }
@@ -150,7 +150,7 @@
         final int size =
                 4/*size*/ + 8/*fileSize*/ + 4/*hash_algorithm*/ + 1/*log2_blocksize*/ + bytesSize(
                         hashingInfo.salt) + bytesSize(hashingInfo.rawRootHash) + bytesSize(
-                        signingInfo.v3Digest) + bytesSize(signingInfo.certificate) + bytesSize(
+                        signingInfo.apkDigest) + bytesSize(signingInfo.certificate) + bytesSize(
                         signingInfo.additionalData);
         ByteBuffer buffer = ByteBuffer.allocate(size).order(ByteOrder.LITTLE_ENDIAN);
         buffer.putInt(size);
@@ -159,7 +159,7 @@
         buffer.put(hashingInfo.log2BlockSize);
         writeBytes(buffer, hashingInfo.salt);
         writeBytes(buffer, hashingInfo.rawRootHash);
-        writeBytes(buffer, signingInfo.v3Digest);
+        writeBytes(buffer, signingInfo.apkDigest);
         writeBytes(buffer, signingInfo.certificate);
         writeBytes(buffer, signingInfo.additionalData);
         return buffer.array();
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index bbc936d..99bdfd1 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -194,4 +194,5 @@
     boolean needsCheckpoint() = 86;
     void abortChanges(in String message, boolean retry) = 87;
     void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88;
+    void fixupAppDir(in String path) = 89;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 1454aac..aee32ed 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -162,7 +162,12 @@
     /** {@hide} */
     public static final String PROP_SETTINGS_FUSE = FeatureFlagUtils.PERSIST_PREFIX
             + FeatureFlagUtils.SETTINGS_FUSE_FLAG;
-
+    /**
+     * Property that determines whether {@link OP_LEGACY_STORAGE} is sticky for
+     * legacy apps.
+     * @hide
+     */
+    public static final String PROP_LEGACY_OP_STICKY = "persist.sys.legacy_storage_sticky";
 
     /** {@hide} */
     public static final String UUID_PRIVATE_INTERNAL = null;
@@ -2470,6 +2475,36 @@
         }
     }
 
+    /**
+     * Asks StorageManager to fixup the permissions of an application-private directory.
+     *
+     * On devices without sdcardfs, filesystem permissions aren't magically fixed up. This
+     * is problematic mostly in application-private directories, which are owned by the
+     * application itself; if another process with elevated permissions creates a file
+     * in these directories, the UID will be wrong, and the owning package won't be able
+     * to access the files.
+     *
+     * This API can be used to recursively fix up the permissions on the passed in path.
+     * The default platform user of this API is the DownloadProvider, which can download
+     * things in application-private directories on their behalf.
+     *
+     * This API doesn't require any special permissions, because it merely changes the
+     * permissions of a directory to what they should anyway be.
+     *
+     * @param path the path for which we should fix up the permissions
+     *
+     * @hide
+     */
+    public void fixupAppDir(@NonNull File path) {
+        try {
+            mStorageManager.fixupAppDir(path.getCanonicalPath());
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to get canonical path for " + path.getPath(), e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** {@hide} */
     private static void setCacheBehavior(File path, String name, boolean enabled)
             throws IOException {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 60f10cd..bbcb9d9 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6564,13 +6564,6 @@
          * Setting specifying if the accessibility shortcut is enabled.
          * @hide
          */
-        public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
-                "accessibility_shortcut_enabled";
-
-        /**
-         * Setting specifying if the accessibility shortcut is enabled.
-         * @hide
-         */
         public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
                 "accessibility_shortcut_on_lock_screen";
 
diff --git a/core/java/android/service/autofill/InlinePresentation.java b/core/java/android/service/autofill/InlinePresentation.java
index a9addba..b6a8ced 100644
--- a/core/java/android/service/autofill/InlinePresentation.java
+++ b/core/java/android/service/autofill/InlinePresentation.java
@@ -49,7 +49,8 @@
     private final @NonNull InlinePresentationSpec mInlinePresentationSpec;
 
     /**
-     * Indicates whether the UI should be pinned, hence non-scrollable, in the host.
+     * Indicates whether the UI should be pinned, hence non-scrollable and non-filterable, in the
+     * host.
      */
     private final boolean mPinned;
 
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 37a75f0..10f526d 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -136,7 +136,8 @@
     /**
      * Response code for the {@code consumer} in
      * {@link ControlsProviderService#performControlAction} indicating that in order for the action
-     * to be performed, acknowledgment from the user is required.
+     * to be performed, acknowledgment from the user is required. Any non-empty string returned
+     * from {@link #getChallengeValue} shall be treated as a positive acknowledgment.
      */
     public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3;
     /**
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 7d070b1..f8265d6 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -780,15 +780,16 @@
             audioCapabilities |= AUDIO_CAPABILITY_NOISE_SUPPRESSION;
         }
 
-        int code = STATUS_ERROR;
+        int code;
         try {
             code = mModelManagementService.startRecognition(
                     mKeyphraseMetadata.id, mLocale.toLanguageTag(), mInternalCallback,
                     new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
                             recognitionExtra, null /* additional data */, audioCapabilities));
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in startRecognition!", e);
+            throw e.rethrowFromSystemServer();
         }
+
         if (code != STATUS_OK) {
             Slog.w(TAG, "startRecognition() failed with error code " + code);
         }
@@ -796,12 +797,12 @@
     }
 
     private int stopRecognitionLocked() {
-        int code = STATUS_ERROR;
+        int code;
         try {
             code = mModelManagementService.stopRecognition(mKeyphraseMetadata.id,
                     mInternalCallback);
         } catch (RemoteException e) {
-            Slog.w(TAG, "RemoteException in stopRecognition!", e);
+            throw e.rethrowFromSystemServer();
         }
 
         if (code != STATUS_OK) {
@@ -968,12 +969,12 @@
                 }
             }
 
-            ModuleProperties dspModuleProperties = null;
+            ModuleProperties dspModuleProperties;
             try {
                 dspModuleProperties =
                         mModelManagementService.getDspModuleProperties();
             } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in getDspProperties!", e);
+                throw e.rethrowFromSystemServer();
             }
 
             // No DSP available
@@ -989,7 +990,7 @@
                 mKeyphraseMetadata = mModelManagementService.getEnrolledKeyphraseMetadata(
                         mText, mLocale.toLanguageTag());
             } catch (RemoteException e) {
-                Slog.w(TAG, "RemoteException in internalUpdateEnrolledKeyphraseMetadata", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index b54e4d9..45d3465 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -35,6 +35,7 @@
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceActionCheckCallback;
@@ -47,6 +48,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -63,6 +65,8 @@
  * separate process from this one.
  */
 public class VoiceInteractionService extends Service {
+    static final String TAG = VoiceInteractionService.class.getSimpleName();
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      * To be supported, the service must also require the
@@ -240,9 +244,22 @@
     public void onReady() {
         mSystemService = IVoiceInteractionManagerService.Stub.asInterface(
                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+        Objects.requireNonNull(mSystemService);
+        try {
+            mSystemService.asBinder().linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException e) {
+            Log.wtf(TAG, "unable to link to death with system service");
+        }
         mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager());
     }
 
+    private IBinder.DeathRecipient mDeathRecipient = () -> {
+        Log.e(TAG, "system service binder died shutting down");
+        Handler.getMain().executeOrSendMessage(PooledLambda.obtainMessage(
+                VoiceInteractionService::onShutdownInternal, VoiceInteractionService.this));
+    };
+
+
     private void onShutdownInternal() {
         onShutdown();
         // Stop any active recognitions when shutting down.
@@ -349,16 +366,24 @@
     }
 
     private void safelyShutdownHotwordDetector() {
-        try {
-            synchronized (mLock) {
-                if (mHotwordDetector != null) {
-                    mHotwordDetector.stopRecognition();
-                    mHotwordDetector.invalidate();
-                    mHotwordDetector = null;
-                }
+        synchronized (mLock) {
+            if (mHotwordDetector == null) {
+                return;
             }
-        } catch (Exception ex) {
-            // Ignore.
+
+            try {
+                mHotwordDetector.stopRecognition();
+            } catch (Exception ex) {
+                // Ignore.
+            }
+
+            try {
+                mHotwordDetector.invalidate();
+            } catch (Exception ex) {
+                // Ignore.
+            }
+
+            mHotwordDetector = null;
         }
     }
 
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index 04be71f..346fe29 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -24,6 +24,7 @@
 import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.pickBestDigestForV4;
 import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
 
 import android.util.ArrayMap;
@@ -117,7 +118,10 @@
         return vSigner.certs;
     }
 
-    private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity)
+    /**
+     * Same as above returns the full signer object, containing additional info e.g. digest.
+     */
+    public static VerifiedSigner verify(String apkFile, boolean verifyIntegrity)
             throws SignatureNotFoundException, SecurityException, IOException {
         try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
             return verify(apk, verifyIntegrity);
@@ -209,9 +213,11 @@
                     verityDigest, apk.length(), signatureInfo);
         }
 
+        byte[] digest = pickBestDigestForV4(contentDigests);
+
         return new VerifiedSigner(
                 signerCerts.toArray(new X509Certificate[signerCerts.size()][]),
-                verityRootHash);
+                verityRootHash, digest);
     }
 
     private static X509Certificate[] verifySigner(
@@ -426,11 +432,14 @@
      */
     public static class VerifiedSigner {
         public final X509Certificate[][] certs;
-        public final byte[] verityRootHash;
 
-        public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash) {
+        public final byte[] verityRootHash;
+        public final byte[] digest;
+
+        public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash, byte[] digest) {
             this.certs = certs;
             this.verityRootHash = verityRootHash;
+            this.digest = digest;
         }
 
     }
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
index 2437af2..4ab541b 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java
@@ -16,8 +16,6 @@
 
 package android.util.apk;
 
-import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256;
-import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512;
 import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256;
 import static android.util.apk.ApkSigningBlockUtils.compareSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getContentDigestAlgorithmJcaDigestAlgorithm;
@@ -26,6 +24,7 @@
 import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm;
 import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorithm;
+import static android.util.apk.ApkSigningBlockUtils.pickBestDigestForV4;
 import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray;
 
 import android.os.Build;
@@ -213,24 +212,11 @@
                     verityDigest, apk.length(), signatureInfo);
         }
 
-        result.digest = pickBestV3DigestForV4(contentDigests);
+        result.digest = pickBestDigestForV4(contentDigests);
 
         return result;
     }
 
-    // Keep in sync with pickBestV3DigestForV4 in apksigner.V3SchemeVerifier.
-    private static byte[] pickBestV3DigestForV4(Map<Integer, byte[]> contentDigests) {
-        final int[] orderedContentDigestTypes =
-                {CONTENT_DIGEST_CHUNKED_SHA512, CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
-                        CONTENT_DIGEST_CHUNKED_SHA256};
-        for (int contentDigestType : orderedContentDigestTypes) {
-            if (contentDigests.containsKey(contentDigestType)) {
-                return contentDigests.get(contentDigestType);
-            }
-        }
-        return null;
-    }
-
     private static VerifiedSigner verifySigner(
             ByteBuffer signerBlock,
             Map<Integer, byte[]> contentDigests,
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
index 8c240d9..d40efce 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java
@@ -145,7 +145,7 @@
                     "Public key mismatch between certificate and signature record");
         }
 
-        return new VerifiedSigner(new Certificate[]{certificate}, signingInfo.v3Digest);
+        return new VerifiedSigner(new Certificate[]{certificate}, signingInfo.apkDigest);
     }
 
     /**
@@ -155,11 +155,11 @@
      */
     public static class VerifiedSigner {
         public final Certificate[] certs;
-        public byte[] v3Digest;
+        public byte[] apkDigest;
 
-        public VerifiedSigner(Certificate[] certs, byte[] v3Digest) {
+        public VerifiedSigner(Certificate[] certs, byte[] apkDigest) {
             this.certs = certs;
-            this.v3Digest = v3Digest;
+            this.apkDigest = apkDigest;
         }
 
     }
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index c1cee48..ab8f80d3 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -184,27 +184,45 @@
             Signature[] signerSigs = convertToSignatures(signerCerts);
 
             if (verifyFull) {
-                // v4 is an add-on and requires v3 signature to validate against its certificates
-                ApkSignatureSchemeV3Verifier.VerifiedSigner nonstreaming =
-                        ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
-                Certificate[][] nonstreamingCerts = new Certificate[][]{nonstreaming.certs};
-                Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts);
+                byte[] nonstreamingDigest = null;
+                Certificate[][] nonstreamingCerts = null;
 
+                try {
+                    // v4 is an add-on and requires v2 or v3 signature to validate against its
+                    // certificate and digest
+                    ApkSignatureSchemeV3Verifier.VerifiedSigner v3Signer =
+                            ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
+                    nonstreamingDigest = v3Signer.digest;
+                    nonstreamingCerts = new Certificate[][]{v3Signer.certs};
+                } catch (SignatureNotFoundException e) {
+                    try {
+                        ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer =
+                                ApkSignatureSchemeV2Verifier.verify(apkPath, false);
+                        nonstreamingDigest = v2Signer.digest;
+                        nonstreamingCerts = v2Signer.certs;
+                    } catch (SignatureNotFoundException ee) {
+                        throw new SecurityException(
+                                "V4 verification failed to collect V2/V3 certificates from : "
+                                        + apkPath, ee);
+                    }
+                }
+
+                Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts);
                 if (nonstreamingSigs.length != signerSigs.length) {
                     throw new SecurityException(
-                            "Invalid number of certificates: " + nonstreaming.certs.length);
+                            "Invalid number of certificates: " + nonstreamingSigs.length);
                 }
 
                 for (int i = 0, size = signerSigs.length; i < size; ++i) {
                     if (!nonstreamingSigs[i].equals(signerSigs[i])) {
-                        throw new SecurityException("V4 signature certificate does not match V3");
+                        throw new SecurityException(
+                                "V4 signature certificate does not match V2/V3");
                     }
                 }
 
-                // TODO(b/151240006): add support for v2 digest and make it mandatory.
-                if (!ArrayUtils.isEmpty(vSigner.v3Digest) && !ArrayUtils.equals(vSigner.v3Digest,
-                        nonstreaming.digest, vSigner.v3Digest.length)) {
-                    throw new SecurityException("V3 digest in V4 signature does not match V3");
+                if (!ArrayUtils.equals(vSigner.apkDigest, nonstreamingDigest,
+                        vSigner.apkDigest.length)) {
+                    throw new SecurityException("APK digest in V4 signature does not match V2/V3");
                 }
             }
 
diff --git a/core/java/android/util/apk/ApkSigningBlockUtils.java b/core/java/android/util/apk/ApkSigningBlockUtils.java
index 4fe8515..2a4b65d 100644
--- a/core/java/android/util/apk/ApkSigningBlockUtils.java
+++ b/core/java/android/util/apk/ApkSigningBlockUtils.java
@@ -421,6 +421,10 @@
     static final int CONTENT_DIGEST_CHUNKED_SHA512 = 2;
     static final int CONTENT_DIGEST_VERITY_CHUNKED_SHA256 = 3;
 
+    private static final int[] V4_CONTENT_DIGEST_ALGORITHMS =
+            {CONTENT_DIGEST_CHUNKED_SHA512, CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
+                    CONTENT_DIGEST_CHUNKED_SHA256};
+
     static int compareSignatureAlgorithm(int sigAlgorithm1, int sigAlgorithm2) {
         int digestAlgorithm1 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm1);
         int digestAlgorithm2 = getSignatureAlgorithmContentDigestAlgorithm(sigAlgorithm2);
@@ -572,6 +576,21 @@
     }
 
     /**
+     * Returns the best digest from the map of available digests.
+     * similarly to compareContentDigestAlgorithm.
+     *
+     * Keep in sync with pickBestDigestForV4 in apksigner's ApkSigningBlockUtils.
+     */
+    static byte[] pickBestDigestForV4(Map<Integer, byte[]> contentDigests) {
+        for (int algo : V4_CONTENT_DIGEST_ALGORITHMS) {
+            if (contentDigests.containsKey(algo)) {
+                return contentDigests.get(algo);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns new byte buffer whose content is a shared subsequence of this buffer's content
      * between the specified start (inclusive) and end (exclusive) positions. As opposed to
      * {@link ByteBuffer#slice()}, the returned buffer's byte order is the same as the source
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index dffcafe..0ccb1e0 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -57,8 +57,8 @@
  * <li>The application display area specifies the part of the display that may contain
  * an application window, excluding the system decorations.  The application display area may
  * be smaller than the real display area because the system subtracts the space needed
- * for decor elements such as the status bar.  Use {@link WindowMetrics#getSize()} to query the
- * application window size.</li>
+ * for decor elements such as the status bar.  Use {@link WindowMetrics#getBounds()} to query the
+ * application window bounds.</li>
  * <li>The real display area specifies the part of the display that contains content
  * including the system decorations.  Even so, the real display area may be smaller than the
  * physical size of the display if the window manager is emulating a smaller display
@@ -673,7 +673,7 @@
      *
      * @param outSize A {@link Point} object to receive the size information.
      * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of
-     * {@link WindowMetrics} and use {@link WindowMetrics#getSize()} instead.
+     * {@link WindowMetrics} and use {@link WindowMetrics#getBounds()} instead.
      */
     @Deprecated
     public void getSize(Point outSize) {
@@ -689,7 +689,7 @@
      * Gets the size of the display as a rectangle, in pixels.
      *
      * @param outSize A {@link Rect} object to receive the size information.
-     * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application
+     * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
      * window area.
      */
     @Deprecated
@@ -755,7 +755,7 @@
     }
 
     /**
-     * @deprecated Use {@link WindowMetrics#getSize()} instead.
+     * @deprecated Use {@link WindowMetrics#getBounds#width()} instead.
      */
     @Deprecated
     public int getWidth() {
@@ -766,7 +766,7 @@
     }
 
     /**
-     * @deprecated Use {@link WindowMetrics#getSize()} instead.
+     * @deprecated Use {@link WindowMetrics#getBounds()#height()} instead.
      */
     @Deprecated
     public int getHeight() {
@@ -1105,7 +1105,7 @@
      * </p>
      *
      * @param outMetrics A {@link DisplayMetrics} object to receive the metrics.
-     * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application
+     * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application
      * window area, and {@link Configuration#densityDpi} to get the current density.
      */
     @Deprecated
diff --git a/core/java/android/view/SurfaceControlViewHost.java b/core/java/android/view/SurfaceControlViewHost.java
index cd22ad6..fe70ff7 100644
--- a/core/java/android/view/SurfaceControlViewHost.java
+++ b/core/java/android/view/SurfaceControlViewHost.java
@@ -192,6 +192,7 @@
         final WindowManager.LayoutParams lp =
                 new WindowManager.LayoutParams(width, height,
                         WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+        lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         setView(view, lp);
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 59fc6e9..c89e0c9 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -176,6 +176,7 @@
     boolean mUseAlpha = false;
     float mSurfaceAlpha = 1f;
     boolean mClipSurfaceToBounds;
+    int mBackgroundColor = Color.BLACK;
 
     @UnsupportedAppUsage
     boolean mHaveFrame = false;
@@ -828,6 +829,12 @@
         }
     }
 
+    private Transaction updateBackgroundColor(Transaction t) {
+        final float[] colorComponents = new float[] { Color.red(mBackgroundColor) / 255.f,
+                Color.green(mBackgroundColor) / 255.f, Color.blue(mBackgroundColor) / 255.f };
+        t.setColor(mBackgroundControl, colorComponents);
+        return t;
+    }
 
     private void releaseSurfaces() {
         mSurfaceAlpha = 1f;
@@ -1000,6 +1007,7 @@
                     }
 
                     updateBackgroundVisibility(mTmpTransaction);
+                    updateBackgroundColor(mTmpTransaction);
                     if (mUseAlpha) {
                         mTmpTransaction.setAlpha(mSurfaceControl, alpha);
                         mSurfaceAlpha = alpha;
@@ -1399,10 +1407,8 @@
             return;
         }
 
-        final float[] colorComponents = new float[] { Color.red(bgColor) / 255.f,
-                Color.green(bgColor) / 255.f, Color.blue(bgColor) / 255.f };
-
-        mTmpTransaction.setColor(mBackgroundControl, colorComponents).apply();
+        mBackgroundColor = bgColor;
+        updateBackgroundColor(mTmpTransaction).apply();
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d69357b..4922917 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3475,7 +3475,7 @@
     /**
      * Flag indicating the field should not have yellow highlight when autofilled.
      */
-    private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x100;
+    private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200;
 
     /* End of masks for mPrivateFlags4 */
 
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 04260c4..4bea623 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -23,11 +23,11 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Rect;
 import android.os.Build;
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
-import android.util.Size;
 import android.util.SparseArray;
 import android.util.TypedValue;
 
@@ -410,8 +410,8 @@
 
         // Size of the screen in bytes, in ARGB_8888 format
         final WindowManager windowManager = context.getSystemService(WindowManager.class);
-        final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
-        mMaximumDrawingCacheSize = 4 * maxWindowSize.getWidth() * maxWindowSize.getHeight();
+        final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
+        mMaximumDrawingCacheSize = 4 * maxWindowBounds.width() * maxWindowBounds.height();
 
         mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 8bf1ade..316a5f2 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -35,7 +35,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.util.Size;
 
 import com.android.internal.os.IResultReceiver;
 
@@ -220,7 +219,7 @@
         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
         final Rect bounds = getCurrentBounds(context);
 
-        return new WindowMetrics(toSize(bounds), computeWindowInsets(bounds));
+        return new WindowMetrics(bounds, computeWindowInsets(bounds));
     }
 
     private static Rect getCurrentBounds(Context context) {
@@ -232,11 +231,7 @@
     @Override
     public WindowMetrics getMaximumWindowMetrics() {
         final Rect maxBounds = getMaximumBounds();
-        return new WindowMetrics(toSize(maxBounds), computeWindowInsets(maxBounds));
-    }
-
-    private Size toSize(Rect frame) {
-        return new Size(frame.width(), frame.height());
+        return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
     }
 
     private Rect getMaximumBounds() {
diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java
index ab5a06e..86ef879 100644
--- a/core/java/android/view/WindowMetrics.java
+++ b/core/java/android/view/WindowMetrics.java
@@ -18,10 +18,10 @@
 
 import android.annotation.NonNull;
 import android.graphics.Point;
-import android.util.Size;
+import android.graphics.Rect;
 
 /**
- * Metrics about a Window, consisting of the size and {@link WindowInsets}.
+ * Metrics about a Window, consisting of the bounds and {@link WindowInsets}.
  * <p>
  * This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and
  * {@link WindowManager#getMaximumWindowMetrics()}.
@@ -31,21 +31,22 @@
  * @see WindowManager#getMaximumWindowMetrics()
  */
 public final class WindowMetrics {
-    private final @NonNull Size mSize;
+    private final @NonNull Rect mBounds;
     private final @NonNull WindowInsets mWindowInsets;
 
-    public WindowMetrics(@NonNull Size size, @NonNull WindowInsets windowInsets) {
-        mSize = size;
+    public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) {
+        mBounds = bounds;
         mWindowInsets = windowInsets;
     }
 
     /**
-     * Returns the size of the window.
+     * Returns the bounds of the area associated with this window or visual context.
      * <p>
-     * <b>Note that this reports a different size than {@link Display#getSize(Point)}.</b>
-     * This method reports the window size including all system bars area, while
-     * {@link Display#getSize(Point)} reports the area excluding navigation bars and display cutout
-     * areas. The value reported by {@link Display#getSize(Point)} can be obtained by using:
+     * <b>Note that the size of the reported bounds can have different size than
+     * {@link Display#getSize(Point)}.</b> This method reports the window size including all system
+     * bar areas, while {@link Display#getSize(Point)} reports the area excluding navigation bars
+     * and display cutout areas. The value reported by {@link Display#getSize(Point)} can be
+     * obtained by using:
      * <pre class="prettyprint">
      * final WindowMetrics metrics = windowManager.getCurrentMetrics();
      * // Gets all excluding insets
@@ -66,16 +67,16 @@
      * </pre>
      * </p>
      *
-     * @return window size in pixel.
+     * @return window bounds in pixels.
      */
-    public @NonNull Size getSize() {
-        return mSize;
+    public @NonNull Rect getBounds() {
+        return mBounds;
     }
 
     /**
-     * Returns the {@link WindowInsets} of the window.
+     * Returns the {@link WindowInsets} of the area associated with this window or visual context.
      *
-     * @return the {@link WindowInsets} of the window.
+     * @return the {@link WindowInsets} of the visual area.
      */
     public @NonNull WindowInsets getWindowInsets() {
         return mWindowInsets;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 39a9ed4..267a5a6 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1242,9 +1242,10 @@
                 if (mLastAutofilledData.containsKey(id)) {
                     value = view.getAutofillValue();
                     valueWasRead = true;
+                    final boolean hideHighlight = mLastAutofilledData.keySet().size() == 1;
 
                     if (Objects.equals(mLastAutofilledData.get(id), value)) {
-                        view.setAutofilled(true, false);
+                        view.setAutofilled(true, hideHighlight);
                     } else {
                         view.setAutofilled(false, false);
                         mLastAutofilledData.remove(id);
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 8d3dc83..2ead352 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -25,7 +25,6 @@
 import android.os.RemoteException;
 import android.transition.Transition;
 import android.util.Log;
-import android.util.Size;
 import android.view.View;
 import android.view.View.OnTouchListener;
 import android.view.ViewTreeObserver;
@@ -129,10 +128,10 @@
             // Gravity.BOTTOM because PopupWindow base class does not expose computeGravity().
             final WindowManager windowManager = anchor.getContext()
                     .getSystemService(WindowManager.class);
-            final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
-            width = windowSize.getWidth();
+            final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
+            width = windowBounds.width();
             if (height != LayoutParams.MATCH_PARENT) {
-                offsetY = windowSize.getHeight() - height;
+                offsetY = windowBounds.height() - height;
             }
             actualAnchor = anchor;
         } else if (virtualBounds != null) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4aeea10..62dd192 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -405,6 +405,13 @@
     // The actual zoom value may changes based on this initial zoom value.
     private float mInitialZoom = 1f;
 
+    // For calculating the line change slops while moving cursor/selection.
+    // The slop max/min value include line height and the slop on the upper/lower line.
+    private static final int LINE_CHANGE_SLOP_MAX_DP = 45;
+    private static final int LINE_CHANGE_SLOP_MIN_DP = 12;
+    private int mLineChangeSlopMax;
+    private int mLineChangeSlopMin;
+
     Editor(TextView textView) {
         mTextView = textView;
         // Synchronize the filter list, which places the undo input filter at the end.
@@ -430,6 +437,14 @@
             logCursor("Editor", "New magnifier is %s.",
                     mNewMagnifierEnabled ? "enabled" : "disabled");
         }
+
+        mLineChangeSlopMax = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, LINE_CHANGE_SLOP_MAX_DP,
+                mTextView.getContext().getResources().getDisplayMetrics());
+        mLineChangeSlopMin = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, LINE_CHANGE_SLOP_MIN_DP,
+                mTextView.getContext().getResources().getDisplayMetrics());
+
     }
 
     @VisibleForTesting
@@ -6018,7 +6033,14 @@
         }
     }
 
-    private int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {
+    @VisibleForTesting
+    public void setLineChangeSlopMinMaxForTesting(final int min, final int max) {
+        mLineChangeSlopMin = min;
+        mLineChangeSlopMax = max;
+    }
+
+    @VisibleForTesting
+    public int getCurrentLineAdjustedForSlop(Layout layout, int prevLine, float y) {
         final int trueLine = mTextView.getLineAtCoordinate(y);
         if (layout == null || prevLine > layout.getLineCount()
                 || layout.getLineCount() <= 0 || prevLine < 0) {
@@ -6031,28 +6053,21 @@
             return trueLine;
         }
 
+        final int lineHeight = layout.getLineBottom(prevLine) - layout.getLineTop(prevLine);
+        int slop = (int)(LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS
+                * (layout.getLineBottom(trueLine) - layout.getLineTop(trueLine)));
+        slop = Math.max(mLineChangeSlopMin,
+                Math.min(mLineChangeSlopMax, lineHeight + slop)) - lineHeight;
+        slop = Math.max(0, slop);
+
         final float verticalOffset = mTextView.viewportToContentVerticalOffset();
-        final int lineCount = layout.getLineCount();
-        final float slop = mTextView.getLineHeight() * LINE_SLOP_MULTIPLIER_FOR_HANDLEVIEWS;
-
-        final float firstLineTop = layout.getLineTop(0) + verticalOffset;
-        final float prevLineTop = layout.getLineTop(prevLine) + verticalOffset;
-        final float yTopBound = Math.max(prevLineTop - slop, firstLineTop + slop);
-
-        final float lastLineBottom = layout.getLineBottom(lineCount - 1) + verticalOffset;
-        final float prevLineBottom = layout.getLineBottom(prevLine) + verticalOffset;
-        final float yBottomBound = Math.min(prevLineBottom + slop, lastLineBottom - slop);
-
-        // Determine if we've moved lines based on y position and previous line.
-        int currLine;
-        if (y <= yTopBound) {
-            currLine = Math.max(prevLine - 1, 0);
-        } else if (y >= yBottomBound) {
-            currLine = Math.min(prevLine + 1, lineCount - 1);
-        } else {
-            currLine = prevLine;
+        if (trueLine > prevLine && y >= layout.getLineBottom(prevLine) + slop + verticalOffset) {
+            return trueLine;
         }
-        return currLine;
+        if (trueLine < prevLine && y <= layout.getLineTop(prevLine) - slop + verticalOffset) {
+            return trueLine;
+        }
+        return prevLine;
     }
 
     /**
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 8943da4..4f14539 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -144,9 +144,6 @@
     @Nullable
     private CharSequence mText;
 
-    // TODO(b/144152069): Remove this after assessing impact on dogfood.
-    private boolean mIsCustomToast;
-
     /**
      * Construct an empty Toast object.  You must call {@link #setView} before you
      * can call {@link #show}.
@@ -214,8 +211,7 @@
                     service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback);
                 }
             } else {
-                service.enqueueTextOrCustomToast(pkg, mToken, tn, mDuration, displayId,
-                        mIsCustomToast);
+                service.enqueueToast(pkg, mToken, tn, mDuration, displayId);
             }
         } catch (RemoteException e) {
             // Empty
@@ -253,7 +249,6 @@
      */
     @Deprecated
     public void setView(View view) {
-        mIsCustomToast = true;
         mNextView = view;
     }
 
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 54ea57a..d64b5f1 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -144,9 +144,6 @@
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
                 false, co, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
-                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
-                false, co, UserHandle.USER_ALL);
-        mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
                 false, co, UserHandle.USER_ALL);
         mContext.getContentResolver().registerContentObserver(
@@ -174,8 +171,6 @@
     public void onSettingsChanged() {
         final boolean hasShortcutTarget = hasShortcutTarget();
         final ContentResolver cr = mContext.getContentResolver();
-        final boolean enabled = Settings.Secure.getIntForUser(
-                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
         // Enable the shortcut from the lockscreen by default if the dialog has been shown
         final int dialogAlreadyShown = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, DialogStaus.NOT_SHOWN,
@@ -183,7 +178,7 @@
         mEnabledOnLockScreen = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
                 dialogAlreadyShown, mUserId) == 1;
-        mIsShortcutEnabled = enabled && hasShortcutTarget;
+        mIsShortcutEnabled = hasShortcutTarget;
     }
 
     /**
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index ae9ce65..c535163 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -387,9 +387,6 @@
         resetViewVisibilitiesForWorkProfileEmptyState(emptyStateView);
         emptyStateView.setVisibility(View.VISIBLE);
 
-        ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon);
-        icon.setImageResource(iconRes);
-
         TextView title = emptyStateView.findViewById(R.id.resolver_empty_state_title);
         title.setText(titleRes);
 
@@ -401,9 +398,17 @@
             subtitle.setVisibility(View.GONE);
         }
 
+        ImageView icon = emptyStateView.findViewById(R.id.resolver_empty_state_icon);
         Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
-        button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
-        button.setOnClickListener(buttonOnClick);
+        if (!getContext().getResources().getBoolean(R.bool.resolver_landscape_phone)) {
+            icon.setVisibility(View.VISIBLE);
+            icon.setImageResource(iconRes);
+            button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
+            button.setOnClickListener(buttonOnClick);
+        } else {
+            icon.setVisibility(View.GONE);
+            button.setVisibility(View.GONE);
+        }
 
         activeListAdapter.markTabLoaded();
     }
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index c408641..51b1334 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -169,13 +169,41 @@
     private static List<AccessibilityButtonTarget> getInstalledServiceTargets(
             @NonNull Context context) {
         final List<AccessibilityButtonTarget> targets = new ArrayList<>();
-        targets.addAll(getAccessibilityServiceTargets(context));
-        targets.addAll(getAccessibilityActivityTargets(context));
+        targets.addAll(getAccessibilityFilteredTargets(context));
         targets.addAll(getWhiteListingServiceTargets(context));
 
         return targets;
     }
 
+    private static List<AccessibilityButtonTarget> getAccessibilityFilteredTargets(
+            @NonNull Context context) {
+        final List<AccessibilityButtonTarget> serviceTargets =
+                getAccessibilityServiceTargets(context);
+        final List<AccessibilityButtonTarget> activityTargets =
+                getAccessibilityActivityTargets(context);
+
+        for (AccessibilityButtonTarget activityTarget : activityTargets) {
+            serviceTargets.removeIf(serviceTarget -> {
+                final ComponentName serviceComponentName =
+                        ComponentName.unflattenFromString(serviceTarget.getId());
+                final ComponentName activityComponentName =
+                        ComponentName.unflattenFromString(activityTarget.getId());
+                final boolean isSamePackageName = activityComponentName.getPackageName().equals(
+                        serviceComponentName.getPackageName());
+                final boolean isSameLabel = activityTarget.getLabel().equals(
+                        serviceTarget.getLabel());
+
+                return isSamePackageName && isSameLabel;
+            });
+        }
+
+        final List<AccessibilityButtonTarget> targets = new ArrayList<>();
+        targets.addAll(serviceTargets);
+        targets.addAll(activityTargets);
+
+        return targets;
+    }
+
     private static List<AccessibilityButtonTarget> getAccessibilityServiceTargets(
             @NonNull Context context) {
         final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a1a434d..dca682e 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2674,7 +2674,7 @@
      */
     private boolean shouldShowStickyContentPreview() {
         return shouldShowStickyContentPreviewNoOrientationCheck()
-                && getResources().getBoolean(R.bool.sharesheet_show_content_preview);
+                && !getResources().getBoolean(R.bool.resolver_landscape_phone);
     }
 
     private boolean shouldShowStickyContentPreviewNoOrientationCheck() {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index ff03f1a..c758989 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -205,9 +205,15 @@
     /** List of packages with the same uid, and its app data info: volume uuid and inode. */
     public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map";
 
+    /** List of whitelisted packages and its app data info: volume uuid and inode. */
+    public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map";
+
     /** Bind mount app storage dirs to lower fs not via fuse */
     public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs";
 
+    /** Bind mount app storage dirs to lower fs not via fuse */
+    public static final String BIND_MOUNT_APP_DATA_DIRS = "--bind-mount-data-dirs";
+
     /**
      * An extraArg passed when a zygote process is forking a child-zygote, specifying a name
      * in the abstract socket namespace. This socket name is what the new child zygote
@@ -313,6 +319,8 @@
      * @param isTopApp true if the process is for top (high priority) application.
      * @param pkgDataInfoList A list that stores related packages and its app data
      * info: volume uuid and inode.
+     * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+     * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
      *
      * @return 0 if this is the child, pid of the child
@@ -321,13 +329,15 @@
     static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            boolean isTopApp, String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+            boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+            boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
         ZygoteHooks.preFork();
 
         int pid = nativeForkAndSpecialize(
                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                 fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
-                pkgDataInfoList, bindMountAppStorageDirs);
+                pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
+                bindMountAppStorageDirs);
         if (pid == 0) {
             // Note that this event ends at the end of handleChildProc,
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -344,6 +354,7 @@
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
             String appDataDir, boolean isTopApp, String[] pkgDataInfoList,
+            String[] whitelistedDataInfoList, boolean bindMountAppDataDirs,
             boolean bindMountAppStorageDirs);
 
     /**
@@ -371,15 +382,19 @@
      * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name,
      * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid,
      * app_b_ce_inode, ...];
+     * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for whitelisted apps.
+     * @param bindMountAppDataDirs  True if the zygote needs to mount data dirs.
      * @param bindMountAppStorageDirs  True if the zygote needs to mount storage dirs.
      */
     private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
-            String[] pkgDataInfoList, boolean bindMountAppStorageDirs) {
+            String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+            boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
         nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
                 niceName, startChildZygote, instructionSet, appDataDir, isTopApp,
-                pkgDataInfoList, bindMountAppStorageDirs);
+                pkgDataInfoList, whitelistedDataInfoList,
+                bindMountAppDataDirs, bindMountAppStorageDirs);
 
         // Note that this event ends at the end of handleChildProc.
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
@@ -399,7 +414,8 @@
     private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp,
-            String[] pkgDataInfoList, boolean bindMountAppStorageDirs);
+            String[] pkgDataInfoList, String[] whitelistedDataInfoList,
+            boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs);
 
     /**
      * Called to do any initialization before starting an application.
@@ -724,7 +740,8 @@
                                  args.mRuntimeFlags, rlimits, args.mMountExternal,
                                  args.mSeInfo, args.mNiceName, args.mStartChildZygote,
                                  args.mInstructionSet, args.mAppDataDir, args.mIsTopApp,
-                                 args.mPkgDataInfoList, args.mBindMountAppStorageDirs);
+                                 args.mPkgDataInfoList, args.mWhitelistedDataInfoList,
+                                 args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
 
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 1a63765..94c1f71 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -227,11 +227,22 @@
     String[] mPkgDataInfoList;
 
     /**
+     * A list that stores all whitelisted app data info: volume uuid and inode.
+     * Null if it does need to do app data isolation.
+     */
+    String[] mWhitelistedDataInfoList;
+
+    /**
      * @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS
      */
     boolean mBindMountAppStorageDirs;
 
     /**
+     * @see Zygote#BIND_MOUNT_APP_DATA_DIRS
+     */
+    boolean mBindMountAppDataDirs;
+
+    /**
      * Constructs instance and parses args
      *
      * @param args zygote command-line args
@@ -452,8 +463,12 @@
                 }
             } else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) {
                 mPkgDataInfoList = getAssignmentList(arg);
+            } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) {
+                mWhitelistedDataInfoList = getAssignmentList(arg);
             } else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) {
                 mBindMountAppStorageDirs = true;
+            } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) {
+                mBindMountAppDataDirs = true;
             } else {
                 break;
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index bc8dfd4..6e880d4 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,8 @@
                 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp,
-                parsedArgs.mPkgDataInfoList, parsedArgs.mBindMountAppStorageDirs);
+                parsedArgs.mPkgDataInfoList,parsedArgs.mWhitelistedDataInfoList,
+                parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
 
         try {
             if (pid == 0) {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 0aeaa47..980943e 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -22,14 +22,10 @@
 import android.annotation.StyleRes;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.graphics.Point;
 import android.graphics.Rect;
-import android.util.Size;
-import android.view.Display;
 import android.view.Gravity;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowMetrics;
 import android.widget.PopupWindow.OnDismissListener;
 
 import com.android.internal.view.menu.MenuPresenter.Callback;
@@ -227,9 +223,9 @@
     @NonNull
     private MenuPopup createPopup() {
         final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
-        final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
+        final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
 
-        final int smallestWidth = Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+        final int smallestWidth = Math.min(maxWindowBounds.width(), maxWindowBounds.height());
         final int minSmallestWidthCascading = mContext.getResources().getDimensionPixelSize(
             com.android.internal.R.dimen.cascading_menus_min_smallest_width);
         final boolean enableCascadingSubmenus = smallestWidth >= minSmallestWidthCascading;
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c83cab7..31527e8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -227,7 +227,7 @@
         }
 
         final int oldCollapsibleHeight = mCollapsibleHeight;
-        mCollapsibleHeight = Math.max(mCollapsibleHeight, getMaxCollapsedHeight());
+        mCollapsibleHeight = Math.min(mCollapsibleHeight, getMaxCollapsedHeight());
 
         if (updateCollapseOffset(oldCollapsibleHeight, !isDragging())) {
             return;
diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp
index 17a02b2..34be2a5 100644
--- a/core/jni/android_media_AudioProductStrategies.cpp
+++ b/core/jni/android_media_AudioProductStrategies.cpp
@@ -85,10 +85,23 @@
     jStrategyId = static_cast<jint>(strategy.getId());
 
     // Audio Attributes Group array
-    std::map<int, std::vector<AudioAttributes> > groups;
+    int attrGroupIndex = 0;
+    std::map<int /**attributesGroupIndex*/, std::vector<AudioAttributes> > groups;
     for (const auto &attr : strategy.getAudioAttributes()) {
-        int attrGroupId = attr.getGroupId();
-        groups[attrGroupId].push_back(attr);
+        int groupId = attr.getGroupId();
+        int streamType = attr.getStreamType();
+        const auto &iter = std::find_if(begin(groups), end(groups),
+                                        [groupId, streamType](const auto &iter) {
+            const auto &frontAttr = iter.second.front();
+            return frontAttr.getGroupId() == groupId && frontAttr.getStreamType() == streamType;
+        });
+        // Same Volume Group Id and same stream type
+        if (iter != end(groups)) {
+             groups[iter->first].push_back(attr);
+        } else {
+            // Add a new Group of AudioAttributes for this product strategy
+            groups[attrGroupIndex++].push_back(attr);
+        }
     }
     numAttributesGroups = groups.size();
 
@@ -97,7 +110,7 @@
     for (const auto &iter : groups) {
         std::vector<AudioAttributes> audioAttributesGroups = iter.second;
         jint numAttributes = audioAttributesGroups.size();
-        jint jGroupId = iter.first;
+        jint jGroupId = audioAttributesGroups.front().getGroupId();
         jint jLegacyStreamType = audioAttributesGroups.front().getStreamType();
 
         jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index ea3c0fa..aa2d1b5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -110,7 +110,6 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 using android::base::GetBoolProperty;
-using android::base::GetProperty;
 
 #define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
                               append(StringPrintf(__VA_ARGS__))
@@ -170,18 +169,6 @@
 
 static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
 
-/**
- * Property to control if app data isolation is enabled.
- */
-static const std::string ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY =
-    "persist.zygote.app_data_isolation";
-
-/**
- * Property to enable app data isolation for sdcard obb or data in vold.
- */
-static const std::string ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
-    "persist.sys.vold_app_data_isolation_enabled";
-
 static constexpr const uint64_t UPPER_HALF_WORD_MASK = 0xFFFF'FFFF'0000'0000;
 static constexpr const uint64_t LOWER_HALF_WORD_MASK = 0x0000'0000'FFFF'FFFF;
 
@@ -1319,20 +1306,13 @@
  * be decrypted after storage is decrypted.
  *
  */
-static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
-    uid_t uid, const char* process_name, jstring managed_nice_name,
-    fail_fn_t fail_fn) {
+static void isolateAppData(JNIEnv* env, const std::vector<std::string>& merged_data_info_list,
+    uid_t uid, const char* process_name,
+    jstring managed_nice_name, fail_fn_t fail_fn) {
 
   const userid_t userId = multiuser_get_user_id(uid);
 
-  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
-
-  int size = (pkg_data_info_list != nullptr) ? env->GetArrayLength(pkg_data_info_list) : 0;
-  // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
-  if ((size % 3) != 0) {
-    fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
-  }
-  ensureInAppMountNamespace(fail_fn);
+  int size = merged_data_info_list.size();
 
   // Mount tmpfs on all possible data directories, so app no longer see the original apps data.
   char internalCePath[PATH_MAX];
@@ -1377,14 +1357,10 @@
   bool legacySymlinkCreated = false;
 
   for (int i = 0; i < size; i += 3) {
-    jstring package_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i));
-    std::string packageName = extract_fn(package_str).value();
+    std::string const & packageName = merged_data_info_list[i];
+    std::string const & volUuid  = merged_data_info_list[i + 1];
+    std::string const & inode = merged_data_info_list[i + 2];
 
-    jstring vol_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 1));
-    std::string volUuid = extract_fn(vol_str).value();
-
-    jstring inode_str = (jstring) (env->GetObjectArrayElement(pkg_data_info_list, i + 2));
-    std::string inode = extract_fn(inode_str).value();
     std::string::size_type sz;
     long long ceDataInode = std::stoll(inode, &sz);
 
@@ -1482,6 +1458,48 @@
   freecon(dataDataContext);
 }
 
+static void insertPackagesToMergedList(JNIEnv* env,
+  std::vector<std::string>& merged_data_info_list,
+  jobjectArray data_info_list, const char* process_name,
+  jstring managed_nice_name, fail_fn_t fail_fn) {
+
+  auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
+
+  int size = (data_info_list != nullptr) ? env->GetArrayLength(data_info_list) : 0;
+  // Size should be a multiple of 3, as it contains list of <package_name, volume_uuid, inode>
+  if ((size % 3) != 0) {
+    fail_fn(CREATE_ERROR("Wrong data_info_list size %d", size));
+  }
+
+  for (int i = 0; i < size; i += 3) {
+    jstring package_str = (jstring) (env->GetObjectArrayElement(data_info_list, i));
+    std::string packageName = extract_fn(package_str).value();
+    merged_data_info_list.push_back(packageName);
+
+    jstring vol_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 1));
+    std::string volUuid = extract_fn(vol_str).value();
+    merged_data_info_list.push_back(volUuid);
+
+    jstring inode_str = (jstring) (env->GetObjectArrayElement(data_info_list, i + 2));
+    std::string inode = extract_fn(inode_str).value();
+    merged_data_info_list.push_back(inode);
+  }
+}
+
+static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list,
+    jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name,
+    jstring managed_nice_name, fail_fn_t fail_fn) {
+
+  ensureInAppMountNamespace(fail_fn);
+  std::vector<std::string> merged_data_info_list;
+  insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list,
+          process_name, managed_nice_name, fail_fn);
+  insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list,
+          process_name, managed_nice_name, fail_fn);
+
+  isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+}
+
 /**
  * Like isolateAppData(), isolate jit profile directories, so apps don't see what
  * other apps are installed by reading content inside /data/misc/profiles/cur.
@@ -1594,7 +1612,9 @@
                              jstring managed_nice_name, bool is_system_server,
                              bool is_child_zygote, jstring managed_instruction_set,
                              jstring managed_app_data_dir, bool is_top_app,
-                             jobjectArray pkg_data_info_list, bool mount_storage_dirs) {
+                             jobjectArray pkg_data_info_list,
+                             jobjectArray whitelisted_data_info_list,
+                             bool mount_data_dirs, bool mount_storage_dirs) {
   const char* process_name = is_system_server ? "system_server" : "zygote";
   auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
   auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1628,9 +1648,9 @@
   // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation.
   // Isolated process / webview / app zygote should be gated by SELinux and file permission
   // so they can't even traverse CE / DE directories.
-  if (pkg_data_info_list != nullptr
-      && GetBoolProperty(ANDROID_APP_DATA_ISOLATION_ENABLED_PROPERTY, true)) {
-    isolateAppData(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
+  if (mount_data_dirs) {
+    isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list,
+            uid, process_name, managed_nice_name, fail_fn);
     isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn);
   }
   if ((mount_external != MOUNT_EXTERNAL_INSTALLER) && mount_storage_dirs) {
@@ -2003,7 +2023,8 @@
         jint mount_external, jstring se_info, jstring nice_name,
         jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
         jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
-        jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+        jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+        jboolean mount_data_dirs, jboolean mount_storage_dirs) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -2041,6 +2062,8 @@
                        mount_external, se_info, nice_name, false,
                        is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
                        is_top_app == JNI_TRUE, pkg_data_info_list,
+                       whitelisted_data_info_list,
+                       mount_data_dirs == JNI_TRUE,
                        mount_storage_dirs == JNI_TRUE);
     }
     return pid;
@@ -2076,7 +2099,8 @@
                        permitted_capabilities, effective_capabilities,
                        MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
                        false, nullptr, nullptr, /* is_top_app= */ false,
-                       /* pkg_data_info_list */ nullptr, false);
+                       /* pkg_data_info_list */ nullptr,
+                       /* whitelisted_data_info_list */ nullptr, false, false);
   } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -2206,15 +2230,16 @@
     jint runtime_flags, jobjectArray rlimits,
     jint mount_external, jstring se_info, jstring nice_name,
     jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app,
-    jobjectArray pkg_data_info_list, jboolean mount_storage_dirs) {
+    jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list,
+    jboolean mount_data_dirs, jboolean mount_storage_dirs) {
   jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
   SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                    capabilities, capabilities,
                    mount_external, se_info, nice_name, false,
                    is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                   is_top_app == JNI_TRUE, pkg_data_info_list,
-                   mount_storage_dirs == JNI_TRUE);
+                   is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list,
+                   mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE);
 }
 
 /**
@@ -2408,7 +2433,7 @@
 static const JNINativeMethod gMethods[] = {
         {"nativeForkAndSpecialize",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
-         "String;Z[Ljava/lang/String;Z)I",
+         "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)I",
          (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize},
         {"nativeForkSystemServer", "(II[II[[IJJ)I",
          (void*)com_android_internal_os_Zygote_nativeForkSystemServer},
@@ -2421,7 +2446,7 @@
         {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
         {"nativeSpecializeAppProcess",
          "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
-         "String;Z[Ljava/lang/String;Z)V",
+         "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V",
          (void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess},
         {"nativeInitNativeState", "(Z)V",
          (void*)com_android_internal_os_Zygote_nativeInitNativeState},
diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto
index 42437d5..563ef14 100644
--- a/core/proto/android/app/enums.proto
+++ b/core/proto/android/app/enums.proto
@@ -203,9 +203,7 @@
     APP_OP_INTERACT_ACROSS_PROFILES = 93;
     APP_OP_ACTIVATE_PLATFORM_VPN = 94;
     APP_OP_LOADER_USAGE_STATS = 95;
-    APP_OP_ACCESS_CALL_AUDIO = 96;
+    APP_OP_DEPRECATED_1 = 96 [deprecated = true];
     APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
     APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98;
 }
-
-
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index ed2c5b2..ab57e3d 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2665,4 +2665,8 @@
     // Open: Settings > Sound > Do Not Disturb > People > Messages
     // OS: R
     DND_MESSAGES = 1839;
+
+    // Open: Settings > Sound > Do Not Disturb > Apps > <Choose App>
+    // OS: R
+    DND_APPS_BYPASSING = 1840;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 84d9ce2..eae6145 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1213,15 +1213,6 @@
                 android:description="@string/permdesc_acceptHandovers"
                 android:protectionLevel="dangerous" />
 
-    <!-- Allows an application assigned to the Dialer role to be granted access to the telephony
-         call audio streams, both TX and RX.
-         <p>Protection level: signature|appop
-    -->
-    <permission android:name="android.permission.ACCESS_CALL_AUDIO"
-                android.label="@string/permlab_accessCallAudio"
-                android:description="@string/permdesc_accessCallAudio"
-                android:protectionLevel="signature|appop" />
-
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
     <!-- ====================================================================== -->
@@ -3654,6 +3645,16 @@
     <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to use the package installer v2 APIs.
+         <p>The package installer v2 APIs are still a work in progress and we're
+         currently validating they work in all scenarios.
+         <p>Not for use by third-party applications.
+         TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+         @hide
+    -->
+    <permission android:name="com.android.permission.USE_INSTALLER_V2"
+        android:protectionLevel="signature|verifier" />
+
     <!-- @SystemApi @TestApi Allows an application to clear user data.
          <p>Not for use by third-party applications
          @hide
diff --git a/core/res/res/layout/resolver_empty_states.xml b/core/res/res/layout/resolver_empty_states.xml
index 210feaf..c7e1a21 100644
--- a/core/res/res/layout/resolver_empty_states.xml
+++ b/core/res/res/layout/resolver_empty_states.xml
@@ -22,11 +22,11 @@
     android:orientation="vertical"
     android:gravity="center_horizontal"
     android:visibility="gone"
+    android:paddingTop="48dp"
     android:paddingStart="24dp"
     android:paddingEnd="24dp">
     <ImageView
         android:id="@+id/resolver_empty_state_icon"
-        android:layout_marginTop="48dp"
         android:layout_width="24dp"
         android:layout_height="24dp"
         android:layout_centerHorizontal="true" />
diff --git a/core/res/res/values-h480dp/bools.xml b/core/res/res/values-h480dp/bools.xml
index 65e3ae6..7896d9b 100644
--- a/core/res/res/values-h480dp/bools.xml
+++ b/core/res/res/values-h480dp/bools.xml
@@ -16,5 +16,5 @@
   -->
 
 <resources>
-    <bool name="sharesheet_show_content_preview">true</bool>
+    <bool name="resolver_landscape_phone">false</bool>
 </resources>
\ No newline at end of file
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d6e200a..2a41542 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1827,19 +1827,14 @@
 
         <attr name="gwpAsanMode" />
 
-        <!-- If {@code true} allow requesting that its permissions don't get automatically
-             revoked when the app is unused for an extended amount of time.
-
-             The default value is {@code false}. -->
-        <attr name="requestAutoRevokePermissionsExemption" format="boolean" />
-
-        <!-- If {@code true} its permissions shouldn't get automatically
-             revoked when the app is unused for an extended amount of time.
-
-             This implies {@code requestDontAutoRevokePermissions=true}
-
-             The default value is {@code false}. -->
+        <!-- @hide no longer used, kept to preserve padding -->
         <attr name="allowAutoRevokePermissionsExemption" format="boolean" />
+
+        <attr name="autoRevokePermissions">
+            <enum name="allowed" value="0" />
+            <enum name="discouraged" value="1" />
+            <enum name="disallowed" value="2" />
+        </attr>
     </declare-styleable>
 
     <!-- An attribution is a logical part of an app and is identified by a tag.
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index c5127dc..fe296c7 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -29,5 +29,5 @@
          <p>The main purpose is for OEMs to customize the rendering of the
          lockscreen, setting this to true should come with customized drawables. -->
     <bool name="use_lock_pattern_drawable">false</bool>
-    <bool name="sharesheet_show_content_preview">false</bool>
+    <bool name="resolver_landscape_phone">true</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f02d54f..738688b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3014,8 +3014,9 @@
       <!-- @hide @SystemApi -->
       <public name="minExtensionVersion" />
       <public name="allowNativeHeapPointerTagging" />
-      <public name="requestAutoRevokePermissionsExemption" />
-      <public name="allowAutoRevokePermissionsExemption" />
+      <!-- @hide no longer used, kept to preserve padding -->
+      <public name="allowAutoRevokePermissionsExemption"/>
+      <public name="autoRevokePermissions" />
       <public name="preserveLegacyExternalStorage" />
       <public name="mimeGroup" />
       <public name="gwpAsanMode" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 06f7760..5b88036 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5482,11 +5482,6 @@
     <!-- Error message. This text lets the user know that their current personal apps can't open this specific content. [CHAR LIMIT=NONE] -->
     <string name="resolver_no_personal_apps_available_resolve">No personal apps can open this content</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_accessCallAudio">Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.</string>
-
     <!-- Icc depersonalization related strings -->
     <!-- Label text for PIN entry widget on SIM Network Depersonalization panel [CHAR LIMIT=none] -->
     <string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY">SIM network unlock PIN</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0adef75..22caf4c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3929,7 +3929,7 @@
   <java-symbol type="dimen" name="resolver_empty_state_height" />
   <java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" />
   <java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" />
-  <java-symbol type="bool" name="sharesheet_show_content_preview" />
+  <java-symbol type="bool" name="resolver_landscape_phone" />
   <java-symbol type="dimen" name="resolver_tab_text_size" />
 
   <!-- Toast message for background started foreground service while-in-use permission restriction feature -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 2ef0c92..88f9fc2 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -702,7 +702,7 @@
     </style>
 
     <style name="Theme.Dream">
-        <item name="windowBackground">@null</item>
+        <item name="windowBackground">@color/black</item>
         <item name="windowDisablePreview">true</item>
     </style>
 
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
index 79b803a..0cd0643e 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
@@ -25,13 +25,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
-import android.util.Size;
 import android.view.Display;
 import android.view.Gravity;
 import android.view.View;
@@ -119,15 +119,15 @@
         @Override
         public void showApplicationOverlay() throws RemoteException {
             final WindowManager wm = mOverlayContext.getSystemService(WindowManager.class);
-            final Size size = wm.getCurrentWindowMetrics().getSize();
+            final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
 
             final WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
                     TYPE_APPLICATION_OVERLAY,
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                             | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                             | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
-            wmlp.width = size.getWidth() / 2;
-            wmlp.height = size.getHeight() / 2;
+            wmlp.width = bounds.width() / 2;
+            wmlp.height = bounds.height() / 2;
             wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
             wmlp.setTitle(TAG);
 
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
index 1737bd0..f48e666 100644
--- a/core/tests/coretests/src/android/content/ContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -236,10 +237,28 @@
     }
 
     @Test
+    public void testGetType_providerException() {
+        String type =
+                mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error"));
+        assertThat(type).isNull();
+    }
+
+    @Test
     public void testCanonicalize() {
         Uri canonical = mResolver.canonicalize(
                 Uri.parse("content://android.content.FakeProviderRemote/something"));
         assertThat(canonical).isEqualTo(
                 Uri.parse("content://android.content.FakeProviderRemote/canonical"));
     }
+
+    @Test
+    public void testCanonicalize_providerException() {
+        try {
+            mResolver.canonicalize(
+                    Uri.parse("content://android.content.FakeProviderRemote/error"));
+            fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            // Expected
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java
index 1d7ba5d..8bc5660 100644
--- a/core/tests/coretests/src/android/content/FakeProviderRemote.java
+++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java
@@ -37,6 +37,9 @@
 
     @Override
     public String getType(Uri uri) {
+        if (uri.getPath() != null && uri.getPath().contains("error")) {
+            throw new IllegalArgumentException("Expected exception");
+        }
         return "fake/remote";
     }
 
@@ -57,6 +60,9 @@
 
     @Override
     public Uri canonicalize(Uri uri) {
+        if (uri.getPath() != null && uri.getPath().contains("error")) {
+            throw new IllegalArgumentException("Expected exception");
+        }
         return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority())
                 .appendPath("canonical").build();
     }
diff --git a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
index df5c9d2..4114b28 100644
--- a/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
+++ b/core/tests/coretests/src/android/content/res/ResourcesManagerTest.java
@@ -184,7 +184,7 @@
     @SmallTest
     public void testThemesGetUpdatedWithNewImpl() {
         Binder activity1 = new Binder();
-        Resources resources1 = mResourcesManager.createBaseActivityResources(
+        Resources resources1 = mResourcesManager.createBaseTokenResources(
                 activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, null,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
@@ -217,7 +217,7 @@
         // Create a Resources for the Activity.
         Configuration config1 = new Configuration();
         config1.densityDpi = 280;
-        Resources resources1 = mResourcesManager.createBaseActivityResources(
+        Resources resources1 = mResourcesManager.createBaseTokenResources(
                 activity1, APP_ONE_RES_DIR, null, null, null, Display.DEFAULT_DISPLAY, config1,
                 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null, null);
         assertNotNull(resources1);
diff --git a/core/tests/coretests/src/android/util/GridScenario.java b/core/tests/coretests/src/android/util/GridScenario.java
index 4809a21..e7ee1cd 100644
--- a/core/tests/coretests/src/android/util/GridScenario.java
+++ b/core/tests/coretests/src/android/util/GridScenario.java
@@ -233,7 +233,7 @@
         // turn off title bar
         requestWindowFeature(Window.FEATURE_NO_TITLE);
 
-        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
 
         final Params params = new Params();
         init(params);
diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/util/ListScenario.java
index d4e5a43..74dc4b4 100644
--- a/core/tests/coretests/src/android/util/ListScenario.java
+++ b/core/tests/coretests/src/android/util/ListScenario.java
@@ -306,7 +306,7 @@
         requestWindowFeature(Window.FEATURE_NO_TITLE);
 
 
-        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
 
         final Params params = createParams();
         init(params);
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index 2c0aa73..ab1a642 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -239,7 +239,7 @@
 
         // for test stability, turn off title bar
         requestWindowFeature(Window.FEATURE_NO_TITLE);
-        int screenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight()
+        int screenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height()
                 - 25;
         mLinearLayout = new LinearLayout(this);
         mLinearLayout.setOrientation(LinearLayout.VERTICAL);
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index e465a85..3038e79 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -17,8 +17,8 @@
 package android.view;
 
 import android.app.Activity;
+import android.graphics.Rect;
 import android.os.Bundle;
-import android.util.Size;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
@@ -39,9 +39,9 @@
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
 
         final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize();
-        final Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
-        final int screenWidth = windowSize.getWidth();
-        final int screenHeight = windowSize.getHeight();
+        final Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+        final int screenWidth = windowBounds.width();
+        final int screenHeight = windowBounds.height();
 
         final View tiny = new View(this);
         tiny.setId(R.id.a);
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index 039387c..46e55fa 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -22,7 +22,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import android.util.Size;
+import android.graphics.Rect;
 import android.widget.TextView;
 
 import androidx.test.filters.LargeTest;
@@ -55,9 +55,9 @@
 
         // Specify start and end coordinates with respect to the window size.
         final WindowManager wm = mScaleGestureActivity.getSystemService(WindowManager.class);
-        final Size windowSize = wm.getCurrentWindowMetrics().getSize();
-        final int windowWidth = windowSize.getWidth();
-        final int windowHeight = windowSize.getHeight();
+        final Rect windowBounds = wm.getCurrentWindowMetrics().getBounds();
+        final int windowWidth = windowBounds.width();
+        final int windowHeight = windowBounds.height();
 
         // Obtain coordinates to perform pinch and zoom from the center, to 75% of the display.
         final int centerX = windowWidth / 2;
diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java
index fa68860..74524bf 100644
--- a/core/tests/coretests/src/android/view/WindowMetricsTest.java
+++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java
@@ -22,10 +22,10 @@
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.platform.test.annotations.Presubmit;
-import android.util.Size;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
@@ -87,10 +87,12 @@
 
     private static void verifyMetricsSanity(WindowMetrics currentMetrics,
             WindowMetrics maxMetrics) {
-        Size currentSize = currentMetrics.getSize();
-        Size maxSize = maxMetrics.getSize();
+        Rect currentBounds = currentMetrics.getBounds();
+        Rect maxBounds = maxMetrics.getBounds();
 
-        assertTrue(maxSize.getWidth() >= currentSize.getWidth());
-        assertTrue(maxSize.getHeight() >= currentSize.getHeight());
+        assertTrue(maxBounds.width() >= currentBounds.width());
+        assertTrue(maxBounds.height() >= currentBounds.height());
+        assertTrue(maxBounds.left >= 0);
+        assertTrue(maxBounds.top >= 0);
     }
 }
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
index ba27fac..eae1bbc 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
@@ -15,11 +15,12 @@
  */
 package android.view.contentcapture;
 
+import static org.mockito.Mockito.mock;
 import static org.testng.Assert.assertThrows;
 
+import android.content.ContentCaptureOptions;
 import android.content.Context;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -37,16 +38,20 @@
     @Mock
     private Context mMockContext;
 
-    private ContentCaptureManager mManager;
-
-    @Before
-    public void before() {
-        mManager = new ContentCaptureManager(mMockContext, /* service= */ null,
-                /* options= */ null);
+    @Test
+    public void testConstructor_invalidParametersThrowsException() {
+        assertThrows(NullPointerException.class,
+                () -> new ContentCaptureManager(mMockContext, /* service= */ null, /* options= */
+                        null));
     }
 
     @Test
-    public void testRemoveData_invalid() {
-        assertThrows(NullPointerException.class, () -> mManager.removeData(null));
+    public void testRemoveData_invalidParametersThrowsException() {
+        final IContentCaptureManager mockService = mock(IContentCaptureManager.class);
+        final ContentCaptureOptions options = new ContentCaptureOptions(null);
+        final ContentCaptureManager manager =
+                new ContentCaptureManager(mMockContext, mockService, options);
+
+        assertThrows(NullPointerException.class, () -> manager.removeData(null));
     }
 }
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index d5825e2..4bd9ccd 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -16,9 +16,9 @@
 
 package android.view.menu;
 
+import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase;
 import android.util.PollingCheck;
-import android.util.Size;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.espresso.ContextMenuUtils;
@@ -81,8 +81,8 @@
      */
     private int getMinScreenDimension() {
         final WindowManager windowManager = getActivity().getSystemService(WindowManager.class);
-        final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
-        return Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+        final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds();
+        return Math.min(maxWindowBounds.width(), maxWindowBounds.height());
     }
 
     /**
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index f81964c..9a93dbf 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
 import static android.widget.espresso.TextViewActions.dragOnText;
 import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
@@ -36,7 +37,11 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
 import android.text.Layout;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.AbsoluteSizeSpan;
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.InputDevice;
@@ -44,7 +49,7 @@
 import android.view.View;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.MediumTest;
 import androidx.test.filters.Suppress;
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
@@ -63,7 +68,8 @@
 import java.util.concurrent.atomic.AtomicLong;
 
 @RunWith(AndroidJUnit4.class)
-@SmallTest
+@MediumTest
+@Presubmit
 public class EditorCursorDragTest {
     private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName();
 
@@ -489,6 +495,38 @@
     }
 
     @Test
+    public void testLineChangeSlop() throws Throwable {
+        TextView tv = mActivity.findViewById(R.id.textview);
+        Spannable s = new SpannableString("a\nb\nc");
+        s.setSpan(new AbsoluteSizeSpan(10), 2, 4, SPAN_INCLUSIVE_EXCLUSIVE);
+        s.setSpan(new AbsoluteSizeSpan(32), 4, 5, SPAN_INCLUSIVE_EXCLUSIVE);
+        mInstrumentation.runOnMainSync(() -> tv.setText(s));
+
+        Layout layout = tv.getLayout();
+        Editor editor = tv.getEditorForTesting();
+        final float verticalOffset = tv.getExtendedPaddingTop();
+        editor.setLineChangeSlopMinMaxForTesting(30, 65);
+        // Hit top part of upper line, jump to upper line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 1, 5 + verticalOffset))
+                .isEqualTo(0);
+        // Hit bottom part of upper line, stay at current line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 1, 40 + verticalOffset))
+                .isEqualTo(1);
+        // Hit current line, stay at current line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 1, 70 + verticalOffset))
+                .isEqualTo(1);
+        // Hit top part of lower line, stay at current line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 1, 85 + verticalOffset))
+                .isEqualTo(1);
+        // Hit bottom part of lower line, jump to lower line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 1, 110 + verticalOffset))
+                .isEqualTo(2);
+        // Hit lower line of lower line, jump to target line.
+        assertThat(editor.getCurrentLineAdjustedForSlop(layout, 0, 110 + verticalOffset))
+                .isEqualTo(2);
+    }
+
+    @Test
     public void testCursorDrag_snapDistance() throws Throwable {
         String text = "line1: This is the 1st line: A\n"
                 + "line2: This is the 2nd line: B\n"
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 3dc001d..ec75e40 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -22,6 +22,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
+import android.platform.test.annotations.Presubmit;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -36,6 +37,7 @@
 
 @RunWith(JUnit4.class)
 @SmallTest
+@Presubmit
 public class EditorTouchStateTest {
 
     private EditorTouchState mTouchState;
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 8e90a82..d51cc32 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -111,7 +111,7 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+        mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
 
         Bundle extras = getIntent().getExtras();
         if (extras != null) {
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index fd1dbfc..5cedd13 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -106,8 +106,8 @@
 
         int firstTop = firstChild.getTop();
 
-        int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getSize()
-                .getHeight();
+        int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getBounds()
+                .height();
         int distance = TouchUtils.dragViewBy(this, firstChild, 
                 Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, (int) (windowHeight * 0.75f));
         
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index e6195b1..5cca766 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -66,7 +66,7 @@
         super.onCreate(savedInstanceState);
 
         final int desiredHeight =
-                (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getSize().getHeight());
+                (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getBounds().height());
 
         mLeftListView = new ListView(this);
         mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
diff --git a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
index 9af0ed0..4a33da6 100644
--- a/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/accessibility/AccessibilityShortcutControllerTest.java
@@ -17,7 +17,6 @@
 package com.android.internal.accessibility;
 
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
-import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
 import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY;
@@ -102,10 +101,8 @@
     private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
 
     // Convenience values for enabling/disabling to make code more readable
-    private static final int DISABLED = 0;
     private static final int ENABLED_EXCEPT_LOCK_SCREEN = 1;
     private static final int ENABLED_INCLUDING_LOCK_SCREEN = 2;
-    private static final int DISABLED_BUT_LOCK_SCREEN_ON = 3;
 
     private @Mock Context mContext;
     private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
@@ -225,14 +222,6 @@
     }
 
     @Test
-    public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse()
-            throws Exception {
-        configureValidShortcutService();
-        configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON);
-        assertFalse(getController().isAccessibilityShortcutAvailable(false));
-    }
-
-    @Test
     public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse()
             throws Exception {
         configureValidShortcutService();
@@ -285,20 +274,8 @@
     }
 
     @Test
-    public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse()
-            throws Exception {
-        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
-        configureValidShortcutService();
-        AccessibilityShortcutController accessibilityShortcutController = getController();
-        configureShortcutEnabled(DISABLED);
-        accessibilityShortcutController.onSettingsChanged();
-        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
-    }
-
-    @Test
     public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue()
             throws Exception {
-        configureShortcutEnabled(DISABLED);
         configureValidShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
         configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
@@ -594,31 +571,19 @@
     }
 
     private void configureShortcutEnabled(int enabledValue) {
-        final boolean enabled;
         final boolean lockscreen;
 
         switch (enabledValue) {
-            case DISABLED:
-                enabled = false;
-                lockscreen = false;
-                break;
-            case DISABLED_BUT_LOCK_SCREEN_ON:
-                enabled = false;
-                lockscreen = true;
-                break;
             case ENABLED_INCLUDING_LOCK_SCREEN:
-                enabled = true;
                 lockscreen = true;
                 break;
             case ENABLED_EXCEPT_LOCK_SCREEN:
-                enabled = true;
                 lockscreen = false;
                 break;
             default:
                 throw new IllegalArgumentException();
         }
 
-        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_ENABLED, enabled ? 1 : 0);
         Settings.Secure.putInt(
                 mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
     }
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index 5c89da0..98f5824 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -61,7 +61,6 @@
   <hidden-api-whitelisted-app package="com.android.terminal" />
   <hidden-api-whitelisted-app package="com.android.wallpaper" />
   <hidden-api-whitelisted-app package="jp.co.omronsoft.openwnn" />
-  <!-- STOPSHIP: Remove this when fixing all @hide usage for tethering.-->
-  <hidden-api-whitelisted-app package="com.android.networkstack.tethering" />
+  <!-- TODO: Remove NetworkStack whitelisting -->
   <hidden-api-whitelisted-app package="com.android.networkstack" />
 </config>
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8b973a1..0a56acc 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -708,6 +708,8 @@
         DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
     }
 
+    public static final String LEGACY_REMOTE_SUBMIX_ADDRESS = "0";
+
     // device states, must match AudioSystem::device_connection_state
     @UnsupportedAppUsage
     public static final int DEVICE_STATE_UNAVAILABLE = 0;
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index c0461bc..1d70a0d 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -46,6 +46,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -3048,16 +3049,47 @@
          * @param block The linear block object
          * @param offset The byte offset into the input buffer at which the data starts.
          * @param size The number of bytes of valid input data.
-         * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
-         *                   may be null for non-encrypted content.
          * @return this object
          * @throws IllegalStateException if a buffer is already set
          */
         public @NonNull QueueRequest setLinearBlock(
                 @NonNull LinearBlock block,
                 int offset,
+                int size) {
+            if (!isAccessible()) {
+                throw new IllegalStateException("The request is stale");
+            }
+            if (mLinearBlock != null || mHardwareBuffer != null) {
+                throw new IllegalStateException("Cannot set block twice");
+            }
+            mLinearBlock = block;
+            mOffset = offset;
+            mSize = size;
+            mCryptoInfo = null;
+            return this;
+        }
+
+        /**
+         * Set an encrypted linear block to this queue request. Exactly one buffer must be
+         * set for a queue request before calling {@link #queue}. It is possible
+         * to use the same {@link LinearBlock} object for multiple queue
+         * requests. The behavior is undefined if the range of the buffer
+         * overlaps for multiple requests, or the application writes into the
+         * region being processed by the codec.
+         *
+         * @param block The linear block object
+         * @param offset The byte offset into the input buffer at which the data starts.
+         * @param size The number of bytes of valid input data.
+         * @param cryptoInfo Metadata describing the structure of the encrypted input sample.
+         * @return this object
+         * @throws IllegalStateException if a buffer is already set
+         */
+        public @NonNull QueueRequest setEncryptedLinearBlock(
+                @NonNull LinearBlock block,
+                int offset,
                 int size,
-                @Nullable MediaCodec.CryptoInfo cryptoInfo) {
+                @NonNull MediaCodec.CryptoInfo cryptoInfo) {
+            Objects.requireNonNull(cryptoInfo);
             if (!isAccessible()) {
                 throw new IllegalStateException("The request is stale");
             }
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index f9dbc50..090f78e 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -374,8 +374,8 @@
         if (refAttr.equals(sDefaultAttributes)) {
             return false;
         }
-        return ((refAttr.getUsage() == AudioAttributes.USAGE_UNKNOWN)
-                || (attr.getUsage() == refAttr.getUsage()))
+        return ((refAttr.getSystemUsage() == AudioAttributes.USAGE_UNKNOWN)
+                || (attr.getSystemUsage() == refAttr.getSystemUsage()))
             && ((refAttr.getContentType() == AudioAttributes.CONTENT_TYPE_UNKNOWN)
                 || (attr.getContentType() == refAttr.getContentType()))
             && ((refAttr.getAllFlags() == 0)
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 29dfd73..9310d38 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -40,6 +40,7 @@
 using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
 using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
+using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
@@ -1382,6 +1383,42 @@
     return dvrObj;
 }
 
+jobject JTuner::getDemuxCaps() {
+    DemuxCapabilities caps;
+    Result res;
+    mTuner->getDemuxCaps([&](Result r, const DemuxCapabilities& demuxCaps) {
+        caps = demuxCaps;
+        res = r;
+    });
+    if (res != Result::SUCCESS) {
+        return NULL;
+    }
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities");
+    jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIIIIJI[IZ)V");
+
+    jint numDemux = caps.numDemux;
+    jint numRecord = caps.numRecord;
+    jint numPlayback = caps.numPlayback;
+    jint numTsFilter = caps.numTsFilter;
+    jint numSectionFilter = caps.numSectionFilter;
+    jint numAudioFilter = caps.numAudioFilter;
+    jint numVideoFilter = caps.numVideoFilter;
+    jint numPesFilter = caps.numPesFilter;
+    jint numPcrFilter = caps.numPcrFilter;
+    jlong numBytesInSectionFilter = caps.numBytesInSectionFilter;
+    jint filterCaps = static_cast<jint>(caps.filterCaps);
+    jboolean bTimeFilter = caps.bTimeFilter;
+
+    jintArray linkCaps = env->NewIntArray(caps.linkCaps.size());
+    env->SetIntArrayRegion(
+            linkCaps, 0, caps.linkCaps.size(), reinterpret_cast<jint*>(&caps.linkCaps[0]));
+
+    return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter,
+            numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter,
+            numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter);
+}
+
 }  // namespace android
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2739,8 +2776,9 @@
     return tuner->openDvr(DvrType::PLAYBACK, bufferSize);
 }
 
-static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) {
-    return NULL;
+static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getDemuxCaps();
 }
 
 static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 5d2bba6..18aac28 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -185,6 +185,7 @@
     jobject openTimeFilter();
     jobject openDescrambler();
     jobject openDvr(DvrType type, jlong bufferSize);
+    jobject getDemuxCaps();
 
 protected:
     Result openDemux();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 2522095..daeb731 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -2210,14 +2210,14 @@
     }
 
     public static Size getPreviewSizeBound(WindowManager windowManager, Size bound) {
-        Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
+        Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds();
 
-        int width = windowSize.getWidth();
-        int height = windowSize.getHeight();
+        int width = windowBounds.width();
+        int height = windowBounds.height();
 
         if (height > width) {
             height = width;
-            width = windowSize.getHeight();
+            width = windowBounds.height();
         }
 
         if (bound.getWidth() <= width &&
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
index d4eb2a9..a2da23e 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
@@ -28,11 +28,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.util.Size;
 import android.util.Slog;
 import android.view.Display;
 import android.view.ViewGroup;
@@ -134,8 +134,8 @@
         }
         lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
         lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
-        Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
-        int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+        Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds();
+        int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height());
         maxSize *= 2;
         lp.x = maxSize;
         lp.y = maxSize;
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
index df00eee..e2120f8 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
@@ -19,22 +19,22 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
-import java.util.ArrayList;
-import java.util.Random;
-
 import android.app.Dialog;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.util.Size;
 import android.view.Display;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 
+import java.util.ArrayList;
+import java.util.Random;
+
 public class FakeBackgroundService extends Service {
     final ArrayList<int[]> mAllocs = new ArrayList<int[]>();
 
@@ -99,8 +99,8 @@
         // Create an instance of WindowManager that is adjusted to the area of the display dedicated
         // for windows with type TYPE_APPLICATION_OVERLAY.
         final WindowManager wm = windowContext.getSystemService(WindowManager.class);
-        Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
-        int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
+        Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds();
+        int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height());
         maxSize *= 2;
         lp.x = maxSize;
         lp.y = maxSize;
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index a2fa461..a95677d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -406,6 +406,10 @@
 
         mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
         mOk.setEnabled(false);
+
+        if (!mOk.isInTouchMode()) {
+            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
+        }
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 2b84196..59735f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -189,19 +189,6 @@
         return context.getString(R.string.config_defaultAccessibilityService);
     }
 
-    /**
-     * Check if the accessibility shortcut is enabled for a user
-     *
-     * @param context A valid context
-     * @param userId  The user of interest
-     * @return {@code true} if the shortcut is enabled for the user. {@code false} otherwise.
-     * Note that the shortcut may be enabled, but no action associated with it.
-     */
-    public static boolean isShortcutEnabled(Context context, int userId) {
-        return Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, userId) == 1;
-    }
-
     private static Set<ComponentName> getInstalledServices(Context context) {
         final Set<ComponentName> installedServices = new HashSet<>();
         installedServices.clear();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index d17f242..a1fba4a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -174,7 +174,7 @@
 
     @Override
     public boolean isEnabled(BluetoothDevice device) {
-        if (mService == null) {
+        if (mService == null || device == null) {
             return false;
         }
         return mService.getConnectionPolicy(device) > CONNECTION_POLICY_FORBIDDEN;
@@ -182,7 +182,7 @@
 
     @Override
     public int getConnectionPolicy(BluetoothDevice device) {
-        if (mService == null) {
+        if (mService == null || device == null) {
             return CONNECTION_POLICY_FORBIDDEN;
         }
         return mService.getConnectionPolicy(device);
@@ -191,7 +191,7 @@
     @Override
     public boolean setEnabled(BluetoothDevice device, boolean enabled) {
         boolean isEnabled = false;
-        if (mService == null) {
+        if (mService == null || device == null) {
             return false;
         }
         if (enabled) {
@@ -213,7 +213,7 @@
     }
 
     public long getHiSyncId(BluetoothDevice device) {
-        if (mService == null) {
+        if (mService == null || device == null) {
             return BluetoothHearingAid.HI_SYNC_ID_INVALID;
         }
         return mService.getHiSyncId(device);
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index c34c365..7ef0801 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -169,6 +169,22 @@
                 sourceMetricsCategory);
     }
 
+    /**
+     * Logs an event when the intent is started by Profile select dialog.
+     *
+     * @return true if the intent is loggable, otherwise false
+     */
+    public boolean logStartedIntentWithProfile(Intent intent, int sourceMetricsCategory,
+            boolean isWorkProfile) {
+        if (intent == null) {
+            return false;
+        }
+        final ComponentName cn = intent.getComponent();
+        final String key = cn != null ? cn.flattenToString() : intent.getAction();
+        return logSettingsTileClick(key + (isWorkProfile ? "/work" : "/personal"),
+                sourceMetricsCategory);
+    }
+
     private boolean logSettingsTileClick(String logKey, int sourceMetricsCategory) {
         if (TextUtils.isEmpty(logKey)) {
             // Not loggable
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 2e144cc..df0de68 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -66,6 +66,7 @@
     private LocalBluetoothManager mLocalBluetoothManager;
     private InfoMediaManager mInfoMediaManager;
     private String mPackageName;
+    private MediaDevice mOnTransferBluetoothDevice;
 
     @VisibleForTesting
     List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
@@ -143,7 +144,7 @@
             final CachedBluetoothDevice cachedDevice =
                     ((BluetoothMediaDevice) device).getCachedDevice();
             if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
-                device.setState(MediaDeviceState.STATE_CONNECTING);
+                mOnTransferBluetoothDevice = connectDevice;
                 cachedDevice.connect();
                 return;
             }
@@ -390,6 +391,10 @@
             mCurrentConnectedDevice = infoMediaDevice != null
                     ? infoMediaDevice : updateCurrentConnectedDevice();
             dispatchDeviceListUpdate();
+            if (mOnTransferBluetoothDevice != null && mOnTransferBluetoothDevice.isConnected()) {
+                connectDevice(mOnTransferBluetoothDevice);
+                mOnTransferBluetoothDevice = null;
+            }
         }
 
         private List<MediaDevice> buildDisconnectedBluetoothDevice() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 8bf48e59..c713d78 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -17,6 +17,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
@@ -36,7 +37,10 @@
 
 import java.util.List;
 
-public class WifiStatusTracker extends ConnectivityManager.NetworkCallback {
+/**
+ * Track status of Wi-Fi for the Sys UI.
+ */
+public class WifiStatusTracker {
     private final Context mContext;
     private final WifiNetworkScoreCache mWifiNetworkScoreCache;
     private final WifiManager mWifiManager;
@@ -55,8 +59,9 @@
             .clearCapabilities()
             .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
             .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
-    private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager
-            .NetworkCallback() {
+    private final NetworkCallback mNetworkCallback = new NetworkCallback() {
+        // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable
+        // and onLinkPropertiesChanged.
         @Override
         public void onCapabilitiesChanged(
                 Network network, NetworkCapabilities networkCapabilities) {
@@ -64,11 +69,35 @@
             mCallback.run();
         }
     };
+    private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() {
+                @Override
+                public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+                    // network is now the default network, and its capabilities are nc.
+                    // This method will always be called immediately after the network becomes the
+                    // default, in addition to any time the capabilities change while the network is
+                    // the default.
+                    mDefaultNetwork = network;
+                    mDefaultNetworkCapabilities = nc;
+                    updateStatusLabel();
+                    mCallback.run();
+                }
+                @Override
+                public void onLost(Network network) {
+                    // The system no longer has a default network.
+                    mDefaultNetwork = null;
+                    mDefaultNetworkCapabilities = null;
+                    updateStatusLabel();
+                    mCallback.run();
+                }
+            };
+    private Network mDefaultNetwork = null;
+    private NetworkCapabilities mDefaultNetworkCapabilities = null;
     private final Runnable mCallback;
 
     private WifiInfo mWifiInfo;
     public boolean enabled;
     public boolean isCaptivePortal;
+    public boolean isDefaultNetwork;
     public int state;
     public boolean connected;
     public String ssid;
@@ -94,11 +123,13 @@
             mWifiNetworkScoreCache.registerListener(mCacheListener);
             mConnectivityManager.registerNetworkCallback(
                     mNetworkRequest, mNetworkCallback, mHandler);
+            mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
         } else {
             mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI,
                     mWifiNetworkScoreCache);
             mWifiNetworkScoreCache.unregisterListener();
             mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
+            mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback);
         }
     }
 
@@ -154,8 +185,17 @@
     }
 
     private void updateStatusLabel() {
-        final NetworkCapabilities networkCapabilities
-                = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork());
+        NetworkCapabilities networkCapabilities;
+        final Network currentWifiNetwork = mWifiManager.getCurrentNetwork();
+        if (currentWifiNetwork != null && currentWifiNetwork.equals(mDefaultNetwork)) {
+            // Wifi is connected and the default network.
+            isDefaultNetwork = true;
+            networkCapabilities = mDefaultNetworkCapabilities;
+        } else {
+            isDefaultNetwork = false;
+            networkCapabilities = mConnectivityManager.getNetworkCapabilities(
+                    mWifiManager.getCurrentNetwork());
+        }
         isCaptivePortal = false;
         if (networkCapabilities != null) {
             if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
index ed0857c..204a933 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java
@@ -164,6 +164,38 @@
     }
 
     @Test
+    public void logStartedIntentWithProfile_isPersonalProfile_shouldTagPersonal() {
+        final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+        final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+                MetricsEvent.SETTINGS_GESTURES, false);
+
+        assertThat(loggable).isTrue();
+        verify(mLogWriter).action(
+                MetricsEvent.SETTINGS_GESTURES,
+                MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+                SettingsEnums.PAGE_UNKNOWN,
+                "pkg/cls/personal",
+                0);
+    }
+
+    @Test
+    public void logStartedIntentWithProfile_isWorkProfile_shouldTagWork() {
+        final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls"));
+
+        final boolean loggable = mProvider.logStartedIntentWithProfile(intent,
+                MetricsEvent.SETTINGS_GESTURES, true);
+
+        assertThat(loggable).isTrue();
+        verify(mLogWriter).action(
+                MetricsEvent.SETTINGS_GESTURES,
+                MetricsEvent.ACTION_SETTINGS_TILE_CLICK,
+                SettingsEnums.PAGE_UNKNOWN,
+                "pkg/cls/work",
+                0);
+    }
+
+    @Test
     public void getAttribution_noActivity_shouldReturnUnknown() {
         assertThat(mProvider.getAttribution(null /* activity */))
                 .isEqualTo(SettingsEnums.PAGE_UNKNOWN);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 6b3a97f..4c61ef5 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -107,8 +108,8 @@
         when(mLocalProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile);
         when(mLocalProfileManager.getHearingAidProfile()).thenReturn(mHapProfile);
 
-        mInfoMediaDevice1 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
-                TEST_PACKAGE_NAME);
+        mInfoMediaDevice1 = spy(new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
+                TEST_PACKAGE_NAME));
         mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
                 TEST_PACKAGE_NAME);
         mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager,
@@ -565,6 +566,34 @@
     }
 
     @Test
+    public void onDeviceListAdded_transferToDisconnectedBluetooth_verifyConnectDevice() {
+        final List<MediaDevice> devices = new ArrayList<>();
+        final MediaDevice currentDevice = mock(MediaDevice.class);
+        final MediaDevice device = mock(BluetoothMediaDevice.class);
+        final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+        mLocalMediaManager.mMediaDevices.add(device);
+        mLocalMediaManager.mMediaDevices.add(currentDevice);
+
+        when(device.getId()).thenReturn(TEST_DEVICE_ID_1);
+        when(currentDevice.getId()).thenReturn(TEST_CURRENT_DEVICE_ID);
+        when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice);
+        when(cachedDevice.isConnected()).thenReturn(false);
+        when(cachedDevice.isBusy()).thenReturn(false);
+
+        mLocalMediaManager.registerCallback(mCallback);
+        mLocalMediaManager.connectDevice(device);
+
+        verify(cachedDevice).connect();
+        when(device.isConnected()).thenReturn(true);
+        mLocalMediaManager.mCurrentConnectedDevice = currentDevice;
+        devices.add(mInfoMediaDevice1);
+        devices.add(currentDevice);
+        mLocalMediaManager.mMediaDeviceCallback.onDeviceListAdded(devices);
+
+        verify(mInfoMediaDevice1).connect();
+    }
+
+    @Test
     public void onRequestFailed_shouldDispatchOnRequestFailed() {
         mLocalMediaManager.registerCallback(mCallback);
 
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index d350d9d..d320df9 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -48,7 +48,6 @@
         Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
         Settings.Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
         Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
-        Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
         Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
         Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
         Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 4d33b62..8801a9c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -25,10 +25,10 @@
 import static android.provider.settings.validators.SettingsValidators.COMPONENT_NAME_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.JSON_OBJECT_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.LOCALE_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
-import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
 import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
 
@@ -82,7 +82,6 @@
                 Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT,
                 ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index af74121..b22caf0 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1781,9 +1781,6 @@
                 Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
                 SecureSettingsProto.Accessibility.LARGE_POINTER_ICON);
         dumpSetting(s, p,
-                Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED,
-                SecureSettingsProto.Accessibility.SHORTCUT_ENABLED);
-        dumpSetting(s, p,
                 Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
                 SecureSettingsProto.Accessibility.SHORTCUT_ON_LOCK_SCREEN);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 5a9d749..2fde87c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3436,7 +3436,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 188;
+            private static final int SETTINGS_VERSION = 189;
 
             private final int mUserId;
 
@@ -4759,6 +4759,23 @@
                     currentVersion = 188;
                 }
 
+                if (currentVersion == 188) {
+                    // Deprecate ACCESSIBILITY_SHORTCUT_ENABLED, and migrate it
+                    // to ACCESSIBILITY_SHORTCUT_TARGET_SERVICE.
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+                    final Setting shortcutEnabled = secureSettings.getSettingLocked(
+                            "accessibility_shortcut_enabled");
+                    if ("0".equals(shortcutEnabled.getValue())) {
+                        // Clear shortcut key targets list setting.
+                        secureSettings.insertSettingLocked(
+                                Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                                "", null /* tag */, false /* makeDefault */,
+                                SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    secureSettings.deleteSettingLocked("accessibility_shortcut_enabled");
+                    currentVersion = 189;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index c7fb00a..4771c41 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -81,6 +81,8 @@
     <uses-permission android:name="android.permission.READ_INPUT_STATE" />
     <uses-permission android:name="android.permission.SET_ORIENTATION" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <!--  TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
+    <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
     <uses-permission android:name="android.permission.MOVE_PACKAGE" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 64e5237..0ae00e1 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1019,8 +1019,11 @@
      * Wraps up bugreport generation and triggers a notification to share the bugreport.
      */
     private void onBugreportFinished(BugreportInfo info) {
+        if (!TextUtils.isEmpty(info.shareTitle)) {
+            info.setTitle(info.shareTitle);
+        }
         Log.d(TAG, "Bugreport finished with title: " + info.getTitle()
-                + " and shareDescription:  " + info.shareDescription);
+                + " and shareDescription: " + info.shareDescription);
         info.finished = new AtomicBoolean(true);
 
         synchronized (mLock) {
@@ -1795,7 +1798,9 @@
 
         /**
          * User-provided, detailed description of the bugreport; when set, will be added to the body
-         * of the {@link Intent#ACTION_SEND_MULTIPLE} intent.
+         * of the {@link Intent#ACTION_SEND_MULTIPLE} intent. This is shown in the app where the
+         * bugreport is being shared as an attachment. This is not related/dependant on
+         * {@code shareDescription}.
          */
         private String description;
 
@@ -2130,7 +2135,6 @@
                 return new BugreportInfo[size];
             }
         };
-
     }
 
     @GuardedBy("mLock")
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 7708b8e..6e1fd20 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -30,8 +30,8 @@
 
     <ImageView
         android:id="@+id/icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="@dimen/control_icon_size"
+        android:layout_height="@dimen/control_icon_size"
         android:paddingTop="@dimen/control_padding_adjustment"
         android:clickable="false"
         android:focusable="false"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 432cd74..ee7f523 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1225,6 +1225,7 @@
     <dimen name="controls_top_margin">44dp</dimen>
     <dimen name="control_header_text_size">22sp</dimen>
     <dimen name="control_text_size">14sp</dimen>
+    <dimen name="control_icon_size">24dp</dimen>
     <dimen name="control_spacing">4dp</dimen>
     <dimen name="control_list_divider">1dp</dimen>
     <dimen name="control_corner_radius">12dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c8c35c7..8a3a16e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -374,9 +374,31 @@
     <string name="biometric_dialog_wrong_password">Wrong password</string>
     <!-- Error string shown when the user enters too many incorrect attempts [CHAR LIMIT=120]-->
     <string name="biometric_dialog_credential_too_many_attempts">Too many incorrect attempts.\nTry again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+
     <!-- Error string shown when the user enters an incorrect PIN/pattern/password and it counts towards the max attempts before the data on the device is wiped. [CHAR LIMIT=NONE]-->
     <string name="biometric_dialog_credential_attempts_before_wipe">Try again. Attempt <xliff:g id="attempts" example="1">%1$d</xliff:g> of <xliff:g id="max_attempts" example="3">%2$d</xliff:g>.</string>
 
+    <!-- Title of a dialog shown when the user only has one attempt left to provide the correct PIN/pattern/password before the device, one of its users, or a work profile is wiped. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_attempt_before_wipe_dialog_title">Your data will be deleted</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the device is wiped. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_device">If you enter an incorrect pattern on the next attempt, this device\u2019s data will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the device is wiped. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_device">If you enter an incorrect PIN on the next attempt, this device\u2019s data will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the device is wiped. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_password_attempt_before_wipe_device">If you enter an incorrect password on the next attempt, this device\u2019s data will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the user is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_user">If you enter an incorrect pattern on the next attempt, this user will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the user is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_user">If you enter an incorrect PIN on the next attempt, this user will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the user is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_password_attempt_before_wipe_user">If you enter an incorrect password on the next attempt, this user will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct pattern before the work profile is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile">If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the work profile is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_profile">If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted.</string>
+    <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the work profile is removed. [CHAR LIMIT=NONE] -->
+    <string name="biometric_dialog_last_password_attempt_before_wipe_profile">If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.</string>
+
     <!-- Content of a dialog shown when the user has failed to provide the device lock too many times and the device is wiped. [CHAR LIMIT=NONE] -->
     <string name="biometric_dialog_failed_attempts_now_wiping_device">Too many incorrect attempts. This device\u2019s data will be deleted.</string>
     <!-- Content of a dialog shown when the user has failed to provide the user lock too many times and the user is removed. [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 49e3e57..3bda3c8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -20,9 +20,7 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -38,7 +36,6 @@
 import android.app.AppGlobals;
 import android.app.IAssistDataReceiver;
 import android.app.WindowConfiguration;
-import android.app.WindowConfiguration.ActivityType;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
@@ -113,15 +110,18 @@
      * @return the top running task (can be {@code null}).
      */
     public ActivityManager.RunningTaskInfo getRunningTask() {
-        return getRunningTask(ACTIVITY_TYPE_RECENTS /* ignoreActivityType */);
+        return getRunningTask(false /* filterVisibleRecents */);
     }
 
-    public ActivityManager.RunningTaskInfo getRunningTask(@ActivityType int ignoreActivityType) {
+    /**
+     * @return the top running task filtering only for tasks that can be visible in the recent tasks
+     * list (can be {@code null}).
+     */
+    public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) {
         // Note: The set of running tasks from the system is ordered by recency
         try {
             List<ActivityManager.RunningTaskInfo> tasks =
-                    ActivityTaskManager.getService().getFilteredTasks(1, ignoreActivityType,
-                            WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
+                    ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents);
             if (tasks.isEmpty()) {
                 return null;
             }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 07bd3a0..1369350 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -73,14 +73,19 @@
     public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9;
     // The search feature is disabled (either by SUW/SysUI/device policy)
     public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10;
-    // The notification panel is expanded and interactive (either locked or unlocked), and the
-    // quick settings is not expanded
+    // The notification panel is expanded and interactive (either locked or unlocked), and quick
+    // settings is expanded.
     public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
     // Winscope tracing is enabled
     public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12;
     // The Assistant gesture should be constrained. It is up to the launcher implementation to
     // decide how to constrain it
     public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 13;
+    // The bubble stack is expanded. This means that the home gesture should be ignored, since a
+    // swipe up is an attempt to close the bubble stack, but that the back gesture should remain
+    // enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble
+    // stack.
+    public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -96,7 +101,8 @@
             SYSUI_STATE_HOME_DISABLED,
             SYSUI_STATE_SEARCH_DISABLED,
             SYSUI_STATE_TRACING_ENABLED,
-            SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED
+            SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED,
+            SYSUI_STATE_BUBBLES_EXPANDED
     })
     public @interface SystemUiStateFlags {}
 
@@ -118,6 +124,7 @@
         str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
         str.add((flags & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0
                 ? "asst_gesture_constrain" : "");
+        str.add((flags & SYSUI_STATE_BUBBLES_EXPANDED) != 0 ? "bubbles_expanded" : "");
         return str.toString();
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
new file mode 100644
index 0000000..487c295
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMedia.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.keyguard
+
+import android.graphics.drawable.Drawable
+
+import java.util.List
+
+/** State for lock screen media controls. */
+data class KeyguardMedia(
+    val foregroundColor: Int,
+    val backgroundColor: Int,
+    val app: String?,
+    val appIcon: Drawable?,
+    val artist: String?,
+    val song: String?,
+    val artwork: Drawable?,
+    val actionIcons: List<Drawable>
+)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
index 4fcacc2..d154434 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMediaPlayer.java
@@ -32,6 +32,9 @@
 
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Observer;
 import androidx.palette.graphics.Palette;
 
 import com.android.internal.util.ContrastColorUtil;
@@ -64,39 +67,47 @@
 
     private final Context mContext;
     private final Executor mBackgroundExecutor;
-    private float mAlbumArtRadius;
-    private int mAlbumArtSize;
-    private View mMediaNotifView;
+    private final KeyguardMediaViewModel mViewModel;
+    private KeyguardMediaObserver mObserver;
 
     @Inject
     public KeyguardMediaPlayer(Context context, @Background Executor backgroundExecutor) {
         mContext = context;
         mBackgroundExecutor = backgroundExecutor;
-        loadDimens();
+        mViewModel = new KeyguardMediaViewModel(context);
     }
 
     /** Binds media controls to a view hierarchy. */
     public void bindView(View v) {
-        if (mMediaNotifView != null) {
+        if (mObserver != null) {
             throw new IllegalStateException("cannot bind views, already bound");
         }
-        mMediaNotifView = v;
-        loadDimens();
+        mViewModel.loadDimens();
+        mObserver = new KeyguardMediaObserver(v);
+        // Control buttons
+        for (int i = 0; i < ACTION_IDS.length; i++) {
+            ImageButton button = v.findViewById(ACTION_IDS[i]);
+            if (button == null) {
+                continue;
+            }
+            final int index = i;
+            button.setOnClickListener(unused -> mViewModel.onActionClick(index));
+        }
+        mViewModel.getKeyguardMedia().observeForever(mObserver);
     }
 
     /** Unbinds media controls. */
     public void unbindView() {
-        if (mMediaNotifView == null) {
+        if (mObserver == null) {
             throw new IllegalStateException("cannot unbind views, nothing bound");
         }
-        mMediaNotifView = null;
+        mViewModel.getKeyguardMedia().removeObserver(mObserver);
+        mObserver = null;
     }
 
     /** Clear the media controls because there isn't an active session. */
     public void clearControls() {
-        if (mMediaNotifView != null) {
-            mMediaNotifView.setVisibility(View.GONE);
-        }
+        mBackgroundExecutor.execute(mViewModel::clearControls);
     }
 
     /**
@@ -110,159 +121,244 @@
      */
     public void updateControls(NotificationEntry entry, Icon appIcon,
             MediaMetadata mediaMetadata) {
-        if (mMediaNotifView == null) {
+        if (mObserver == null) {
             throw new IllegalStateException("cannot update controls, views not bound");
         }
         if (mediaMetadata == null) {
-            mMediaNotifView.setVisibility(View.GONE);
-            Log.d(TAG, "media metadata was null");
+            Log.d(TAG, "media metadata was null, closing media controls");
+            // Note that clearControls() executes on the same background executor, so there
+            // shouldn't be an issue with an outdated update running after clear. However, if stale
+            // controls are observed then consider removing any enqueued updates.
+            clearControls();
             return;
         }
-        mMediaNotifView.setVisibility(View.VISIBLE);
+        mBackgroundExecutor.execute(() -> mViewModel.updateControls(entry, appIcon, mediaMetadata));
+    }
 
-        Notification notif = entry.getSbn().getNotification();
+    /** ViewModel for KeyguardMediaControls. */
+    private static final class KeyguardMediaViewModel {
 
-        // Computed foreground and background color based on album art.
-        int fgColor = notif.color;
-        int bgColor = entry.getRow() == null ? -1 : entry.getRow().getCurrentBackgroundTint();
-        Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
-        if (artworkBitmap == null) {
-            artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
-        }
-        if (artworkBitmap != null) {
-            // If we have art, get colors from that
-            Palette p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
-                    .generate();
-            Palette.Swatch swatch = MediaNotificationProcessor.findBackgroundSwatch(p);
-            bgColor = swatch.getRgb();
-            fgColor = MediaNotificationProcessor.selectForegroundColor(bgColor, p);
-        }
-        // Make sure colors will be legible
-        boolean isDark = !ContrastColorUtil.isColorLight(bgColor);
-        fgColor = ContrastColorUtil.resolveContrastColor(mContext, fgColor, bgColor,
-                isDark);
-        fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark);
+        private final Context mContext;
+        private final MutableLiveData<KeyguardMedia> mMedia = new MutableLiveData<>();
+        private final Object mActionsLock = new Object();
+        private List<PendingIntent> mActions;
+        private float mAlbumArtRadius;
+        private int mAlbumArtSize;
 
-        // Album art
-        ImageView albumView = mMediaNotifView.findViewById(R.id.album_art);
-        if (albumView != null) {
-            // Resize art in a background thread
-            final Bitmap bm = artworkBitmap;
-            mBackgroundExecutor.execute(() -> processAlbumArt(bm, albumView));
+        KeyguardMediaViewModel(Context context) {
+            mContext = context;
+            loadDimens();
         }
 
-        // App icon
-        ImageView appIconView = mMediaNotifView.findViewById(R.id.icon);
-        if (appIconView != null) {
-            Drawable iconDrawable = appIcon.loadDrawable(mContext);
-            iconDrawable.setTint(fgColor);
-            appIconView.setImageDrawable(iconDrawable);
+        /** Close the media player because there isn't an active session. */
+        public void clearControls() {
+            synchronized (mActionsLock) {
+                mActions = null;
+            }
+            mMedia.postValue(null);
         }
 
-        // App name
-        TextView appName = mMediaNotifView.findViewById(R.id.app_name);
-        if (appName != null) {
+        /** Update the media player with information about the active session. */
+        public void updateControls(NotificationEntry entry, Icon appIcon,
+                MediaMetadata mediaMetadata) {
+
+            // Foreground and Background colors computed from album art
+            Notification notif = entry.getSbn().getNotification();
+            int fgColor = notif.color;
+            int bgColor = entry.getRow() == null ? -1 : entry.getRow().getCurrentBackgroundTint();
+            Bitmap artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+            if (artworkBitmap == null) {
+                artworkBitmap = mediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+            }
+            if (artworkBitmap != null) {
+                // If we have art, get colors from that
+                Palette p = MediaNotificationProcessor.generateArtworkPaletteBuilder(artworkBitmap)
+                        .generate();
+                Palette.Swatch swatch = MediaNotificationProcessor.findBackgroundSwatch(p);
+                bgColor = swatch.getRgb();
+                fgColor = MediaNotificationProcessor.selectForegroundColor(bgColor, p);
+            }
+            // Make sure colors will be legible
+            boolean isDark = !ContrastColorUtil.isColorLight(bgColor);
+            fgColor = ContrastColorUtil.resolveContrastColor(mContext, fgColor, bgColor,
+                    isDark);
+            fgColor = ContrastColorUtil.ensureTextContrast(fgColor, bgColor, isDark);
+
+            // Album art
+            RoundedBitmapDrawable artwork = null;
+            if (artworkBitmap != null) {
+                Bitmap original = artworkBitmap.copy(Bitmap.Config.ARGB_8888, true);
+                Bitmap scaled = Bitmap.createScaledBitmap(original, mAlbumArtSize, mAlbumArtSize,
+                        false);
+                artwork = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
+                artwork.setCornerRadius(mAlbumArtRadius);
+            }
+
+            // App name
             Notification.Builder builder = Notification.Builder.recoverBuilder(mContext, notif);
-            String appNameString = builder.loadHeaderAppName();
-            appName.setText(appNameString);
-            appName.setTextColor(fgColor);
-        }
+            String app = builder.loadHeaderAppName();
 
-        // Song name
-        TextView titleText = mMediaNotifView.findViewById(R.id.header_title);
-        if (titleText != null) {
-            String songName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
-            titleText.setText(songName);
-            titleText.setTextColor(fgColor);
-        }
+            // App Icon
+            Drawable appIconDrawable = appIcon.loadDrawable(mContext);
 
-        // Artist name
-        TextView artistText = mMediaNotifView.findViewById(R.id.header_artist);
-        if (artistText != null) {
-            String artistName = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
-            artistText.setText(artistName);
-            artistText.setTextColor(fgColor);
-        }
+            // Song name
+            String song = mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
 
-        // Background color
-        if (mMediaNotifView instanceof MediaHeaderView) {
-            MediaHeaderView head = (MediaHeaderView) mMediaNotifView;
-            head.setBackgroundColor(bgColor);
-        }
+            // Artist name
+            String artist = mediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
 
-        // Control buttons
-        final List<Icon> icons = new ArrayList<>();
-        final List<PendingIntent> intents = new ArrayList<>();
-        Notification.Action[] actions = notif.actions;
-        final int[] actionsToShow = notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
+            // Control buttons
+            List<Drawable> actionIcons = new ArrayList<>();
+            final List<PendingIntent> intents = new ArrayList<>();
+            Notification.Action[] actions = notif.actions;
+            final int[] actionsToShow = notif.extras.getIntArray(
+                    Notification.EXTRA_COMPACT_ACTIONS);
 
-        for (int i = 0; i < ACTION_IDS.length; i++) {
-            if (actionsToShow != null && actions != null && i < actionsToShow.length
-                    && actionsToShow[i] < actions.length) {
-                final int idx = actionsToShow[i];
-                icons.add(actions[idx].getIcon());
-                intents.add(actions[idx].actionIntent);
-            } else {
-                icons.add(null);
-                intents.add(null);
+            Context packageContext = entry.getSbn().getPackageContext(mContext);
+            for (int i = 0; i < ACTION_IDS.length; i++) {
+                if (actionsToShow != null && actions != null && i < actionsToShow.length
+                        && actionsToShow[i] < actions.length) {
+                    final int idx = actionsToShow[i];
+                    actionIcons.add(actions[idx].getIcon().loadDrawable(packageContext));
+                    intents.add(actions[idx].actionIntent);
+                } else {
+                    actionIcons.add(null);
+                    intents.add(null);
+                }
             }
+            synchronized (mActionsLock) {
+                mActions = intents;
+            }
+
+            KeyguardMedia data = new KeyguardMedia(fgColor, bgColor, app, appIconDrawable, artist,
+                    song, artwork, actionIcons);
+            mMedia.postValue(data);
         }
 
-        Context packageContext = entry.getSbn().getPackageContext(mContext);
-        for (int i = 0; i < ACTION_IDS.length; i++) {
-            ImageButton button = mMediaNotifView.findViewById(ACTION_IDS[i]);
-            if (button == null) {
-                continue;
+        /** Gets state for the lock screen media controls. */
+        public LiveData<KeyguardMedia> getKeyguardMedia() {
+            return mMedia;
+        }
+
+        /**
+         * Handle user clicks on media control buttons (actions).
+         *
+         * @param index position of the button that was clicked.
+         */
+        public void onActionClick(int index) {
+            PendingIntent intent = null;
+            // This might block the ui thread to wait for the lock. Currently, however, the
+            // lock is held by the bg thread to assign a member, which should be fast. An
+            // alternative could be to add the intents to the state and let the observer set
+            // the onClick listeners.
+            synchronized (mActionsLock) {
+                if (mActions != null && index < mActions.size()) {
+                    intent = mActions.get(index);
+                }
             }
-            Icon icon = icons.get(i);
-            if (icon == null) {
-                button.setVisibility(View.GONE);
-            } else {
-                button.setVisibility(View.VISIBLE);
-                button.setImageDrawable(icon.loadDrawable(packageContext));
-                button.setImageTintList(ColorStateList.valueOf(fgColor));
-                final PendingIntent intent = intents.get(i);
-                if (intent != null) {
-                    button.setOnClickListener(v -> {
-                        try {
-                            intent.send();
-                        } catch (PendingIntent.CanceledException e) {
-                            Log.d(TAG, "failed to send action intent", e);
-                        }
-                    });
+            if (intent != null) {
+                try {
+                    intent.send();
+                } catch (PendingIntent.CanceledException e) {
+                    Log.d(TAG, "failed to send action intent", e);
                 }
             }
         }
+
+        void loadDimens() {
+            mAlbumArtRadius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
+            mAlbumArtSize = (int) mContext.getResources().getDimension(
+                    R.dimen.qs_media_album_size);
+        }
     }
 
-    /**
-     * Process album art for layout
-     * @param albumArt bitmap to use for album art
-     * @param albumView view to hold the album art
-     */
-    private void processAlbumArt(Bitmap albumArt, ImageView albumView) {
-        RoundedBitmapDrawable roundedDrawable = null;
-        if (albumArt != null) {
-            Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
-            Bitmap scaled = Bitmap.createScaledBitmap(original, mAlbumArtSize, mAlbumArtSize,
-                    false);
-            roundedDrawable = RoundedBitmapDrawableFactory.create(mContext.getResources(), scaled);
-            roundedDrawable.setCornerRadius(mAlbumArtRadius);
-        } else {
-            Log.e(TAG, "No album art available");
+    /** Observer for state changes of lock screen media controls. */
+    private static final class KeyguardMediaObserver implements Observer<KeyguardMedia> {
+
+        private final View mRootView;
+        private final MediaHeaderView mMediaHeaderView;
+        private final ImageView mAlbumView;
+        private final ImageView mAppIconView;
+        private final TextView mAppNameView;
+        private final TextView mTitleView;
+        private final TextView mArtistView;
+        private final List<ImageButton> mButtonViews = new ArrayList<>();
+
+        KeyguardMediaObserver(View v) {
+            mRootView = v;
+            mMediaHeaderView = v instanceof MediaHeaderView ? (MediaHeaderView) v : null;
+            mAlbumView = v.findViewById(R.id.album_art);
+            mAppIconView = v.findViewById(R.id.icon);
+            mAppNameView = v.findViewById(R.id.app_name);
+            mTitleView = v.findViewById(R.id.header_title);
+            mArtistView = v.findViewById(R.id.header_artist);
+            for (int i = 0; i < ACTION_IDS.length; i++) {
+                mButtonViews.add(v.findViewById(ACTION_IDS[i]));
+            }
         }
 
-        // Now that it's resized, update the UI
-        final RoundedBitmapDrawable result = roundedDrawable;
-        albumView.post(() -> {
-            albumView.setImageDrawable(result);
-            albumView.setVisibility(result == null ? View.GONE : View.VISIBLE);
-        });
-    }
+        /** Updates lock screen media player views when state changes. */
+        @Override
+        public void onChanged(KeyguardMedia data) {
+            if (data == null) {
+                mRootView.setVisibility(View.GONE);
+                return;
+            }
+            mRootView.setVisibility(View.VISIBLE);
 
-    private void loadDimens() {
-        mAlbumArtRadius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
-        mAlbumArtSize = (int) mContext.getResources().getDimension(
-                    R.dimen.qs_media_album_size);
+            // Background color
+            if (mMediaHeaderView != null) {
+                mMediaHeaderView.setBackgroundColor(data.getBackgroundColor());
+            }
+
+            // Album art
+            if (mAlbumView != null) {
+                mAlbumView.setImageDrawable(data.getArtwork());
+                mAlbumView.setVisibility(data.getArtwork() == null ? View.GONE : View.VISIBLE);
+            }
+
+            // App icon
+            if (mAppIconView != null) {
+                Drawable iconDrawable = data.getAppIcon();
+                iconDrawable.setTint(data.getForegroundColor());
+                mAppIconView.setImageDrawable(iconDrawable);
+            }
+
+            // App name
+            if (mAppNameView != null) {
+                String appNameString = data.getApp();
+                mAppNameView.setText(appNameString);
+                mAppNameView.setTextColor(data.getForegroundColor());
+            }
+
+            // Song name
+            if (mTitleView != null) {
+                mTitleView.setText(data.getSong());
+                mTitleView.setTextColor(data.getForegroundColor());
+            }
+
+            // Artist name
+            if (mArtistView != null) {
+                mArtistView.setText(data.getArtist());
+                mArtistView.setTextColor(data.getForegroundColor());
+            }
+
+            // Control buttons
+            for (int i = 0; i < ACTION_IDS.length; i++) {
+                ImageButton button = mButtonViews.get(i);
+                if (button == null) {
+                    continue;
+                }
+                Drawable icon = data.getActionIcons().get(i);
+                if (icon == null) {
+                    button.setVisibility(View.GONE);
+                    button.setImageDrawable(null);
+                } else {
+                    button.setVisibility(View.VISIBLE);
+                    button.setImageDrawable(icon);
+                    button.setImageTintList(ColorStateList.valueOf(data.getForegroundColor()));
+                }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 13f3c0f..b006bc1 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -347,21 +347,35 @@
             showError(message);
         }
 
-        // Only show popup dialog before wipe.
+        // Only show dialog if <=1 attempts are left before wiping.
         final int remainingAttempts = maxAttempts - numAttempts;
-        if (remainingAttempts <= 0) {
-            showNowWipingMessage();
-            mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR);
+        if (remainingAttempts == 1) {
+            showLastAttemptBeforeWipeDialog();
+        } else if (remainingAttempts <= 0) {
+            showNowWipingDialog();
         }
         return true;
     }
 
-    private void showNowWipingMessage() {
+    private void showLastAttemptBeforeWipeDialog() {
+        final AlertDialog alertDialog = new AlertDialog.Builder(mContext)
+                .setTitle(R.string.biometric_dialog_last_attempt_before_wipe_dialog_title)
+                .setMessage(
+                        getLastAttemptBeforeWipeMessageRes(getUserTypeForWipe(), mCredentialType))
+                .setPositiveButton(android.R.string.ok, null)
+                .create();
+        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
+        alertDialog.show();
+    }
+
+    private void showNowWipingDialog() {
         final AlertDialog alertDialog = new AlertDialog.Builder(mContext)
                 .setMessage(getNowWipingMessageRes(getUserTypeForWipe()))
                 .setPositiveButton(R.string.biometric_dialog_now_wiping_dialog_dismiss, null)
+                .setOnDismissListener(
+                        dialog -> mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR))
                 .create();
-        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
         alertDialog.show();
     }
 
@@ -377,6 +391,59 @@
         }
     }
 
+    private static @StringRes int getLastAttemptBeforeWipeMessageRes(
+            @UserType int userType, @Utils.CredentialType int credentialType) {
+        switch (userType) {
+            case USER_TYPE_PRIMARY:
+                return getLastAttemptBeforeWipeDeviceMessageRes(credentialType);
+            case USER_TYPE_MANAGED_PROFILE:
+                return getLastAttemptBeforeWipeProfileMessageRes(credentialType);
+            case USER_TYPE_SECONDARY:
+                return getLastAttemptBeforeWipeUserMessageRes(credentialType);
+            default:
+                throw new IllegalArgumentException("Unrecognized user type:" + userType);
+        }
+    }
+
+    private static @StringRes int getLastAttemptBeforeWipeDeviceMessageRes(
+            @Utils.CredentialType int credentialType) {
+        switch (credentialType) {
+            case Utils.CREDENTIAL_PIN:
+                return R.string.biometric_dialog_last_pin_attempt_before_wipe_device;
+            case Utils.CREDENTIAL_PATTERN:
+                return R.string.biometric_dialog_last_pattern_attempt_before_wipe_device;
+            case Utils.CREDENTIAL_PASSWORD:
+            default:
+                return R.string.biometric_dialog_last_password_attempt_before_wipe_device;
+        }
+    }
+
+    private static @StringRes int getLastAttemptBeforeWipeProfileMessageRes(
+            @Utils.CredentialType int credentialType) {
+        switch (credentialType) {
+            case Utils.CREDENTIAL_PIN:
+                return R.string.biometric_dialog_last_pin_attempt_before_wipe_profile;
+            case Utils.CREDENTIAL_PATTERN:
+                return R.string.biometric_dialog_last_pattern_attempt_before_wipe_profile;
+            case Utils.CREDENTIAL_PASSWORD:
+            default:
+                return R.string.biometric_dialog_last_password_attempt_before_wipe_profile;
+        }
+    }
+
+    private static @StringRes int getLastAttemptBeforeWipeUserMessageRes(
+            @Utils.CredentialType int credentialType) {
+        switch (credentialType) {
+            case Utils.CREDENTIAL_PIN:
+                return R.string.biometric_dialog_last_pin_attempt_before_wipe_user;
+            case Utils.CREDENTIAL_PATTERN:
+                return R.string.biometric_dialog_last_pattern_attempt_before_wipe_user;
+            case Utils.CREDENTIAL_PASSWORD:
+            default:
+                return R.string.biometric_dialog_last_password_attempt_before_wipe_user;
+        }
+    }
+
     private static @StringRes int getNowWipingMessageRes(@UserType int userType) {
         switch (userType) {
             case USER_TYPE_PRIMARY:
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index c9ce8a1..01c2faa 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -74,6 +74,7 @@
 import com.android.systemui.R;
 import com.android.systemui.bubbles.dagger.BubbleModule;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.PinnedStackListenerForwarder;
@@ -174,6 +175,7 @@
 
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private IStatusBarService mBarService;
+    private SysUiState mSysUiState;
 
     // Used for determining view rect for touch interaction
     private Rect mTempRect = new Rect();
@@ -290,11 +292,12 @@
             NotifPipeline notifPipeline,
             FeatureFlags featureFlags,
             DumpManager dumpManager,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            SysUiState sysUiState) {
         this(context, notificationShadeWindowController, statusBarStateController, shadeController,
                 data, null /* synchronizer */, configurationController, interruptionStateProvider,
                 zenModeController, notifUserManager, groupManager, entryManager,
-                notifPipeline, featureFlags, dumpManager, floatingContentCoordinator);
+                notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
     }
 
     /**
@@ -315,7 +318,8 @@
             NotifPipeline notifPipeline,
             FeatureFlags featureFlags,
             DumpManager dumpManager,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            SysUiState sysUiState) {
         dumpManager.registerDumpable(TAG, this);
         mContext = context;
         mShadeController = shadeController;
@@ -340,6 +344,7 @@
         });
 
         configurationController.addCallback(this /* configurationListener */);
+        mSysUiState = sysUiState;
 
         mBubbleData = data;
         mBubbleData.setListener(mBubbleDataListener);
@@ -593,7 +598,8 @@
     private void ensureStackViewCreated() {
         if (mStackView == null) {
             mStackView = new BubbleStackView(
-                    mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator);
+                    mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
+                    mSysUiState);
             ViewGroup nsv = mNotificationShadeWindowController.getNotificationShadeView();
             int bubbleScrimIndex = nsv.indexOfChild(nsv.findViewById(R.id.scrim_for_bubble));
             int stackIndex = bubbleScrimIndex + 1;  // Show stack above bubble scrim.
@@ -957,9 +963,10 @@
             String key = orderedKeys[i];
             NotificationEntry entry = mNotificationEntryManager.getPendingOrActiveNotif(key);
             rankingMap.getRanking(key, mTmpRanking);
-            if (mBubbleData.hasBubbleWithKey(key) && !mTmpRanking.canBubble()) {
+            boolean isActiveBubble = mBubbleData.hasBubbleWithKey(key);
+            if (isActiveBubble && !mTmpRanking.canBubble()) {
                 mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED);
-            } else if (entry != null && mTmpRanking.isBubble()) {
+            } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) {
                 entry.setFlagBubble(true);
                 onEntryUpdated(entry);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 077ffd3..2bd1518 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -208,7 +208,7 @@
                 b -> {
                     notificationEntryUpdated(bubble, /* suppressFlyout */
                             false, /* showInShade */ true);
-                    setSelectedBubbleInternal(bubble);
+                    setSelectedBubble(bubble);
                 },
                 mContext, stack, factory);
         dispatchPendingChanges();
@@ -233,6 +233,7 @@
                 Bubble b = mOverflowBubbles.get(i);
                 if (b.getKey().equals(entry.getKey())) {
                     moveOverflowBubbleToPending(b);
+                    b.setEntry(entry);
                     return b;
                 }
             }
@@ -240,6 +241,7 @@
             for (int i = 0; i < mPendingBubbles.size(); i++) {
                 Bubble b = mPendingBubbles.get(i);
                 if (b.getKey().equals(entry.getKey())) {
+                    b.setEntry(entry);
                     return b;
                 }
             }
@@ -759,6 +761,17 @@
     }
 
     @VisibleForTesting(visibility = PRIVATE)
+    Bubble getOverflowBubbleWithKey(String key) {
+        for (int i = 0; i < mOverflowBubbles.size(); i++) {
+            Bubble bubble = mOverflowBubbles.get(i);
+            if (bubble.getKey().equals(key)) {
+                return bubble;
+            }
+        }
+        return null;
+    }
+
+    @VisibleForTesting(visibility = PRIVATE)
     void setTimeSource(TimeSource timeSource) {
         mTimeSource = timeSource;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 541c8cf..7191a20 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -80,6 +80,8 @@
 import com.android.systemui.bubbles.animation.ExpandedAnimationController;
 import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
 import com.android.systemui.bubbles.animation.StackAnimationController;
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.util.DismissCircleView;
 import com.android.systemui.util.FloatingContentCoordinator;
@@ -241,6 +243,7 @@
 
     private BubbleTouchHandler mTouchHandler;
     private BubbleController.BubbleExpandListener mExpandListener;
+    private SysUiState mSysUiState;
 
     private boolean mViewUpdatedRequested = false;
     private boolean mIsExpansionAnimating = false;
@@ -437,7 +440,8 @@
 
     public BubbleStackView(Context context, BubbleData data,
             @Nullable SurfaceSynchronizer synchronizer,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            SysUiState sysUiState) {
         super(context);
 
         mBubbleData = data;
@@ -445,6 +449,8 @@
         mTouchHandler = new BubbleTouchHandler(this, data, context);
         setOnTouchListener(mTouchHandler);
 
+        mSysUiState = sysUiState;
+
         Resources res = getResources();
         mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered);
         mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size);
@@ -1055,6 +1061,11 @@
         if (shouldExpand == mIsExpanded) {
             return;
         }
+
+        mSysUiState
+                .setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
+                .commitUpdate(mContext.getDisplayId());
+
         if (mIsExpanded) {
             animateCollapse();
             logBubbleEvent(mExpandedBubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index 27c9e98..e84e932 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -21,6 +21,7 @@
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.bubbles.BubbleData;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -62,7 +63,8 @@
             NotifPipeline notifPipeline,
             FeatureFlags featureFlags,
             DumpManager dumpManager,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            SysUiState sysUiState) {
         return new BubbleController(
                 context,
                 notificationShadeWindowController,
@@ -79,6 +81,7 @@
                 notifPipeline,
                 featureFlags,
                 dumpManager,
-                floatingContentCoordinator);
+                floatingContentCoordinator,
+                sysUiState);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 6c49c82..118fcbb 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -252,10 +252,17 @@
                                     it.controlId in favoritesForComponentKeys
                                 )
                             }
+                            val removedControls = mutableListOf<ControlStatus>()
+                            Favorites.getStructuresForComponent(componentName).forEach { st ->
+                                st.controls.forEach {
+                                    if (it.controlId in removed) {
+                                        val r = createRemovedStatus(componentName, it, st.structure)
+                                        removedControls.add(r)
+                                    }
+                                }
+                            }
                             val loadData = createLoadDataObject(
-                                Favorites.getControlsForComponent(componentName)
-                                    .filter { it.controlId in removed }
-                                    .map { createRemovedStatus(componentName, it) } +
+                                removedControls +
                                 controlsWithFavorite,
                                 favoritesForComponentKeys
                             )
@@ -266,17 +273,15 @@
                     override fun error(message: String) {
                         loadCanceller = null
                         executor.execute {
-                            val loadData = Favorites.getControlsForComponent(componentName)
-                                .let { controls ->
-                                val keys = controls.map { it.controlId }
-                                createLoadDataObject(
-                                        controls.map {
-                                            createRemovedStatus(componentName, it, false)
-                                        },
-                                        keys,
-                                        true
-                                )
-                            }
+                            val controls = Favorites.getStructuresForComponent(componentName)
+                                    .flatMap { st ->
+                                        st.controls.map {
+                                            createRemovedStatus(componentName, it, st.structure,
+                                                    false)
+                                        }
+                                    }
+                            val keys = controls.map { it.control.controlId }
+                            val loadData = createLoadDataObject(controls, keys, true)
                             dataCallback.accept(loadData)
                         }
                     }
@@ -372,6 +377,7 @@
     private fun createRemovedStatus(
         componentName: ComponentName,
         controlInfo: ControlInfo,
+        structure: CharSequence,
         setRemoved: Boolean = true
     ): ControlStatus {
         val intent = Intent(Intent.ACTION_MAIN).apply {
@@ -384,6 +390,8 @@
                 0)
         val control = Control.StatelessBuilder(controlInfo.controlId, pendingIntent)
                 .setTitle(controlInfo.controlTitle)
+                .setSubtitle(controlInfo.controlSubtitle)
+                .setStructure(structure)
                 .setDeviceType(controlInfo.deviceType)
                 .build()
         return ControlStatus(control, componentName, true, setRemoved)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
index 15c2a0a..a7a4103 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -34,24 +34,29 @@
 
 /**
  * Creates all dialogs for challengeValues that can occur from a call to
- * {@link ControlsProviderService#performControlAction}. The types of challenge
- * responses are listed in {@link ControlAction.ResponseResult}.
+ * [ControlsProviderService#performControlAction]. The types of challenge responses are listed in
+ * [ControlAction.ResponseResult].
  */
 object ChallengeDialogs {
 
-    fun createPinDialog(cvh: ControlViewHolder): Dialog? {
+    private const val WINDOW_TYPE = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
+    private const val STYLE = android.R.style.Theme_DeviceDefault_Dialog_Alert
+
+    /**
+     * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_PIN] and
+     * [ControlAction#RESPONSE_CHALLENGE_PIN] responses, decided by the useAlphaNumeric
+     * parameter.
+     */
+    fun createPinDialog(cvh: ControlViewHolder, useAlphaNumeric: Boolean): Dialog? {
         val lastAction = cvh.lastAction
         if (lastAction == null) {
             Log.e(ControlsUiController.TAG,
                 "PIN Dialog attempted but no last action is set. Will not show")
             return null
         }
-        val builder = AlertDialog.Builder(
-            cvh.context,
-            android.R.style.Theme_DeviceDefault_Dialog_Alert
-        ).apply {
+        val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
             val res = cvh.context.resources
-            setTitle(res.getString(R.string.controls_pin_verify, *arrayOf(cvh.title.getText())))
+            setTitle(res.getString(R.string.controls_pin_verify, cvh.title.getText()))
             setView(R.layout.controls_dialog_pin)
             setPositiveButton(
                 android.R.string.ok,
@@ -71,25 +76,64 @@
         }
         return builder.create().apply {
             getWindow().apply {
-                setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+                setType(WINDOW_TYPE)
                 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
             }
             setOnShowListener(DialogInterface.OnShowListener { _ ->
                 val editText = requireViewById<EditText>(R.id.controls_pin_input)
-                requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { v ->
-                    if ((v as CheckBox).isChecked) {
-                        editText.setInputType(
-                            InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
-                    } else {
-                        editText.setInputType(
-                            InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
-                    }
+                val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha)
+                useAlphaCheckBox.setChecked(useAlphaNumeric)
+                setInputType(editText, useAlphaCheckBox.isChecked())
+                requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ ->
+                    setInputType(editText, useAlphaCheckBox.isChecked())
                 }
                 editText.requestFocus()
             })
         }
     }
 
+    /**
+     * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type.
+     */
+    fun createConfirmationDialog(cvh: ControlViewHolder): Dialog? {
+        val lastAction = cvh.lastAction
+        if (lastAction == null) {
+            Log.e(ControlsUiController.TAG,
+                "Confirmation Dialog attempted but no last action is set. Will not show")
+            return null
+        }
+        val builder = AlertDialog.Builder(cvh.context, STYLE).apply {
+            val res = cvh.context.resources
+            setMessage(res.getString(
+                R.string.controls_confirmation_message, cvh.title.getText()))
+            setPositiveButton(
+                android.R.string.ok,
+                DialogInterface.OnClickListener { dialog, _ ->
+                    cvh.action(addChallengeValue(lastAction, "true"))
+                    dialog.dismiss()
+            })
+            setNegativeButton(
+                android.R.string.cancel,
+                DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+            )
+        }
+        return builder.create().apply {
+            getWindow().apply {
+                setType(WINDOW_TYPE)
+            }
+        }
+    }
+
+    private fun setInputType(editText: EditText, useTextInput: Boolean) {
+        if (useTextInput) {
+            editText.setInputType(
+                InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD)
+        } else {
+            editText.setInputType(
+                InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD)
+        }
+    }
+
     private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
         val id = action.getTemplateId()
         return when (action) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 9f5dd02..7d3a860 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -21,6 +21,7 @@
 import android.graphics.drawable.GradientDrawable
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
+import android.service.controls.DeviceTypes
 import android.service.controls.actions.ControlAction
 import android.service.controls.templates.ControlTemplate
 import android.service.controls.templates.StatelessTemplate
@@ -156,7 +157,11 @@
         statusExtra.setTextColor(fg)
 
         icon.setImageDrawable(ri.icon)
-        icon.setImageTintList(fg)
+
+        // do not color app icons
+        if (deviceType != DeviceTypes.TYPE_ROUTINE) {
+            icon.setImageTintList(fg)
+        }
 
         (clipLayer.getDrawable() as GradientDrawable).apply {
             setColor(context.getResources().getColor(bg, context.getTheme()))
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index b0db437..05a0c45 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -442,7 +442,15 @@
             controlViewsById.get(key)?.let { cvh ->
                 when (response) {
                     ControlAction.RESPONSE_CHALLENGE_PIN -> {
-                        activeDialog = ChallengeDialogs.createPinDialog(cvh)
+                        activeDialog = ChallengeDialogs.createPinDialog(cvh, false)
+                        activeDialog?.show()
+                    }
+                    ControlAction.RESPONSE_CHALLENGE_PASSPHRASE -> {
+                        activeDialog = ChallengeDialogs.createPinDialog(cvh, true)
+                        activeDialog?.show()
+                    }
+                    ControlAction.RESPONSE_CHALLENGE_ACK -> {
+                        activeDialog = ChallengeDialogs.createConfirmationDialog(cvh)
                         activeDialog?.show()
                     }
                     else -> cvh.actionResponse(response)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 27e4649..810ea65 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -64,7 +64,7 @@
 
             val iconState = deviceIconMap.getValue(iconKey)
             val resourceId = iconState[enabled]
-            var icon: Drawable? = null
+            var icon: Drawable?
             if (resourceId == APP_ICON_ID) {
                 icon = appIconMap.get(componentName)
                 if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index c495c58..f79c8b2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -64,12 +64,13 @@
 
         val gestureListener = ToggleRangeGestureListener(cvh.layout)
         val gestureDetector = GestureDetector(context, gestureListener)
-        cvh.layout.setOnTouchListener { _: View, e: MotionEvent ->
+        cvh.layout.setOnTouchListener { v: View, e: MotionEvent ->
             if (gestureDetector.onTouchEvent(e)) {
                 return@setOnTouchListener true
             }
 
             if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) {
+                v.getParent().requestDisallowInterceptTouchEvent(false)
                 gestureListener.isDragging = false
                 endUpdateRange()
                 return@setOnTouchListener true
@@ -254,6 +255,7 @@
             yDiff: Float
         ): Boolean {
             if (!isDragging) {
+                v.getParent().requestDisallowInterceptTouchEvent(true)
                 this@ToggleRangeBehavior.beginUpdateRange()
                 isDragging = true
             }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 09d7d26..b329991 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -490,6 +490,9 @@
         public void onPowerSaveChanged(boolean active) {
             if (mDozeHost.isPowerSaveActive()) {
                 mMachine.requestState(DozeMachine.State.DOZE);
+            } else if (mMachine.getState() == DozeMachine.State.DOZE
+                    && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
+                mMachine.requestState(DozeMachine.State.DOZE_AOD);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 73539f9..6514ca4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1849,7 +1849,7 @@
                     .alpha(1)
                     .translationX(0)
                     .translationY(0)
-                    .setDuration(300)
+                    .setDuration(450)
                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                     .setUpdateListener(animation -> {
                         float animatedValue = animation.getAnimatedFraction();
@@ -1878,7 +1878,7 @@
                     .alpha(0)
                     .translationX(mGlobalActionsLayout.getAnimationOffsetX())
                     .translationY(mGlobalActionsLayout.getAnimationOffsetY())
-                    .setDuration(300)
+                    .setDuration(550)
                     .withEndAction(this::completeDismiss)
                     .setInterpolator(new LogAccelerateInterpolator())
                     .setUpdateListener(animation -> {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 2cc3d9e..96494cf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -305,7 +305,8 @@
                 oldInstance.onDestroy();
             }
             mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern);
-            mPendingIntent = PendingIntent.getActivity(getContext(), 0, new Intent(), 0);
+            mPendingIntent = PendingIntent.getActivity(getContext(), 0,
+                    new Intent(getContext(), KeyguardSliceProvider.class), 0);
             mMediaManager.addCallback(this);
             mStatusBarStateController.addCallback(this);
             mNextAlarmController.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index 1a01cfe..0b07655 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -99,14 +99,14 @@
         mEnablePipResize = DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 PIP_USER_RESIZE,
-                /* defaultValue = */ false);
+                /* defaultValue = */ true);
         deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mMainExecutor,
                 new DeviceConfig.OnPropertiesChangedListener() {
                     @Override
                     public void onPropertiesChanged(DeviceConfig.Properties properties) {
                         if (properties.getKeyset().contains(PIP_USER_RESIZE)) {
                             mEnablePipResize = properties.getBoolean(
-                                    PIP_USER_RESIZE, /* defaultValue = */ false);
+                                    PIP_USER_RESIZE, /* defaultValue = */ true);
                         }
                     }
                 });
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5ccf8c7..33cc086 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -133,6 +133,9 @@
             new LocalMediaManager.DeviceCallback() {
         @Override
         public void onDeviceListUpdate(List<MediaDevice> devices) {
+            if (mLocalMediaManager == null) {
+                return;
+            }
             MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice();
             // Check because this can be called several times while changing devices
             if (mDevice == null || !mDevice.equals(currentDevice)) {
@@ -293,14 +296,17 @@
         if (mMediaPlayers.size() > 0) {
             ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE);
 
-            // Set up listener for device changes
-            // TODO: integrate with MediaTransferManager?
-            InfoMediaManager imm =
-                    new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
-            mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, null);
-            mLocalMediaManager.startScan();
-            mDevice = mLocalMediaManager.getCurrentConnectedDevice();
-            mLocalMediaManager.registerCallback(mDeviceCallback);
+            if (mLocalMediaManager == null) {
+                // Set up listener for device changes
+                // TODO: integrate with MediaTransferManager?
+                InfoMediaManager imm =
+                        new InfoMediaManager(mContext, null, null, mLocalBluetoothManager);
+                mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm,
+                        null);
+                mLocalMediaManager.startScan();
+                mDevice = mLocalMediaManager.getCurrentConnectedDevice();
+                mLocalMediaManager.registerCallback(mDeviceCallback);
+            }
         }
     }
 
@@ -323,8 +329,11 @@
         mMediaCarousel.removeView(player.getView());
         if (mMediaPlayers.size() == 0) {
             ((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
-            mLocalMediaManager.stopScan();
-            mLocalMediaManager.unregisterCallback(mDeviceCallback);
+            if (mLocalMediaManager != null) {
+                mLocalMediaManager.stopScan();
+                mLocalMediaManager.unregisterCallback(mDeviceCallback);
+                mLocalMediaManager = null;
+            }
         }
         return true;
     }
@@ -397,6 +406,7 @@
         if (mLocalMediaManager != null) {
             mLocalMediaManager.stopScan();
             mLocalMediaManager.unregisterCallback(mDeviceCallback);
+            mLocalMediaManager = null;
         }
         super.onDetachedFromWindow();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index aa64449..3b3d9dd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -17,7 +17,6 @@
 package com.android.systemui.recents;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 
 import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT;
@@ -27,8 +26,7 @@
 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT;
 import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT;
 import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS;
-import static com.android.systemui.shared.system.LauncherEventUtil
-        .RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
+import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP;
 import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP;
 import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE;
 
@@ -139,7 +137,7 @@
 
         private void onAppLaunch() {
             ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance()
-                    .getRunningTask(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */);
+                    .getRunningTask();
             if (info == null) {
                 return;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
index 3cdc01d..dea8c32 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserObservable.java
@@ -38,7 +38,7 @@
         @Override
         protected void onInactive() {
             super.onInactive();
-            mTracker.startTracking();
+            mTracker.stopTracking();
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 3879c16..1aa7831 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -25,6 +25,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -129,6 +130,7 @@
 
     private int mDividerInsets;
     private final Display mDefaultDisplay;
+    private boolean mSupportSplitScreenMultiWindow;
 
     private int mDividerSize;
     private int mTouchElevation;
@@ -282,6 +284,8 @@
         final DisplayManager displayManager =
                 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
         mDefaultDisplay = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        mSupportSplitScreenMultiWindow =
+                ActivityTaskManager.supportsSplitScreenMultiWindow(mContext);
     }
 
     @Override
@@ -354,6 +358,11 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!mSupportSplitScreenMultiWindow) {
+            super.onLayout(changed, left, top, right, bottom);
+            return;
+        }
+
         if (mFirstLayout) {
             // Wait for first layout so that the ViewRootImpl surface has been created.
             initializeSurfaceState();
@@ -1085,6 +1094,13 @@
         crop.offsetTo(-(otherTaskRect.left - otherRect.left),
                 -(otherTaskRect.top - otherRect.top));
         t.setWindowCrop(mTiles.mSecondarySurface, crop);
+        // Reposition home and recents surfaces or they would be positioned relatively to its
+        // parent (split-screen secondary task) position.
+        for (int i = mTiles.mHomeAndRecentsSurfaces.size() - 1; i >= 0; --i) {
+            t.setPosition(mTiles.mHomeAndRecentsSurfaces.get(i),
+                    mTiles.mHomeBounds.left - otherTaskRect.left,
+                    mTiles.mHomeBounds.top - otherTaskRect.top);
+        }
         final SurfaceControl dividerCtrl = getWindowSurfaceControl();
         if (dividerCtrl != null) {
             if (isHorizontalDivision()) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index c4089e5..6cb7f4f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -26,12 +26,15 @@
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration;
+import android.graphics.Rect;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.Display;
-import android.window.ITaskOrganizer;
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
+import android.window.ITaskOrganizer;
+
+import java.util.ArrayList;
 
 class SplitScreenTaskOrganizer extends ITaskOrganizer.Stub {
     private static final String TAG = "SplitScreenTaskOrganizer";
@@ -43,6 +46,8 @@
     SurfaceControl mSecondarySurface;
     SurfaceControl mPrimaryDim;
     SurfaceControl mSecondaryDim;
+    ArrayList<SurfaceControl> mHomeAndRecentsSurfaces = new ArrayList<>();
+    Rect mHomeBounds = new Rect();
     final Divider mDivider;
 
     SplitScreenTaskOrganizer(Divider divider) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 8724e49..6ed7afe 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -29,9 +29,9 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.Display;
+import android.view.WindowManagerGlobal;
 import android.window.IWindowContainer;
 import android.window.WindowContainerTransaction;
-import android.view.WindowManagerGlobal;
 import android.window.WindowOrganizer;
 
 import com.android.internal.annotations.GuardedBy;
@@ -157,6 +157,7 @@
         for (int i = homeStacks.size() - 1; i >= 0; --i) {
             wct.setBounds(homeStacks.get(i), homeBounds);
         }
+        layout.mTiles.mHomeBounds.set(homeBounds);
         return isHomeResizable;
     }
 
@@ -180,13 +181,17 @@
             if (rootTasks.isEmpty()) {
                 return false;
             }
+            tiles.mHomeAndRecentsSurfaces.clear();
             for (int i = rootTasks.size() - 1; i >= 0; --i) {
-                if (rootTasks.get(i).configuration.windowConfiguration.getWindowingMode()
+                final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
+                if (isHomeOrRecentTask(rootTask)) {
+                    tiles.mHomeAndRecentsSurfaces.add(rootTask.token.getLeash());
+                }
+                if (rootTask.configuration.windowConfiguration.getWindowingMode()
                         != WINDOWING_MODE_FULLSCREEN) {
                     continue;
                 }
-                wct.reparent(rootTasks.get(i).token, tiles.mSecondary.token,
-                        true /* onTop */);
+                wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
             }
             boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
             WindowOrganizer.applyTransaction(wct);
@@ -213,6 +218,7 @@
             // Set launch root first so that any task created after getChildContainers and
             // before reparent (pretty unlikely) are put into fullscreen.
             TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
+            tiles.mHomeAndRecentsSurfaces.clear();
             // TODO(task-org): Once task-org is more complete, consider using Appeared/Vanished
             //                 plus specific APIs to clean this up.
             List<ActivityManager.RunningTaskInfo> primaryChildren =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 8945f36..a3faa80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -67,32 +67,9 @@
     private var updateScheduled: Boolean = false
     private var shadeExpansion = 0f
     @VisibleForTesting
-    var shadeSpring = SpringAnimation(this, object :
-            FloatPropertyCompat<NotificationShadeDepthController>("shadeBlurRadius") {
-        override fun setValue(rect: NotificationShadeDepthController?, value: Float) {
-            shadeBlurRadius = value.toInt()
-        }
-
-        override fun getValue(rect: NotificationShadeDepthController?): Float {
-            return shadeBlurRadius.toFloat()
-        }
-    })
-    private val zoomInterpolator = Interpolators.ACCELERATE_DECELERATE
-
-    /**
-     * Radius that we're animating to.
-     */
-    private var pendingShadeBlurRadius = -1
-
-    /**
-     * Shade blur radius on the current frame.
-     */
-    private var shadeBlurRadius = 0
-        set(value) {
-            if (field == value) return
-            field = value
-            scheduleUpdate()
-        }
+    var shadeSpring = DepthAnimation()
+    @VisibleForTesting
+    var globalActionsSpring = DepthAnimation()
 
     /**
      * Blur radius of the wake-up animation on this frame.
@@ -103,7 +80,6 @@
             field = value
             scheduleUpdate()
         }
-    private var globalDialogVisibility = 0f
 
     /**
      * Callback that updates the window blur value and is called only once per frame.
@@ -111,12 +87,9 @@
     private val updateBlurCallback = Choreographer.FrameCallback {
         updateScheduled = false
 
-        val blur = max(shadeBlurRadius,
-                max(wakeAndUnlockBlurRadius, blurUtils.blurRadiusOfRatio(globalDialogVisibility)))
+        val blur = max(max(shadeSpring.radius, wakeAndUnlockBlurRadius), globalActionsSpring.radius)
         blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
-        val rawZoom = max(blurUtils.ratioOfBlurRadius(blur), globalDialogVisibility)
-        wallpaperManager.setWallpaperZoomOut(root.windowToken,
-                zoomInterpolator.getInterpolation(rawZoom))
+        wallpaperManager.setWallpaperZoomOut(root.windowToken, blurUtils.ratioOfBlurRadius(blur))
         notificationShadeWindowController.setBackgroundBlurRadius(blur)
     }
 
@@ -163,8 +136,9 @@
         }
 
         override fun onDozingChanged(isDozing: Boolean) {
-            if (isDozing && shadeSpring.isRunning) {
-                shadeSpring.skipToEnd()
+            if (isDozing) {
+                shadeSpring.finishIfRunning()
+                globalActionsSpring.finishIfRunning()
             }
         }
     }
@@ -174,10 +148,6 @@
         if (WAKE_UP_ANIMATION_ENABLED) {
             keyguardStateController.addCallback(keyguardStateCallback)
         }
-        shadeSpring.spring = SpringForce(0.0f)
-        shadeSpring.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
-        shadeSpring.spring.stiffness = SpringForce.STIFFNESS_LOW
-        shadeSpring.addEndListener { _, _, _, _ -> pendingShadeBlurRadius = -1 }
         statusBarStateController.addCallback(statusBarStateCallback)
     }
 
@@ -198,11 +168,7 @@
             newBlur = blurUtils.blurRadiusOfRatio(shadeExpansion)
         }
 
-        if (pendingShadeBlurRadius == newBlur) {
-            return
-        }
-        pendingShadeBlurRadius = newBlur
-        shadeSpring.animateToFinalPosition(newBlur.toFloat())
+        shadeSpring.animateTo(newBlur)
     }
 
     private fun scheduleUpdate(viewToBlur: View? = null) {
@@ -215,19 +181,72 @@
     }
 
     fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) {
-        if (visibility == globalDialogVisibility) {
-            return
-        }
-        globalDialogVisibility = visibility
-        scheduleUpdate(dialogView)
+        globalActionsSpring.animateTo(blurUtils.blurRadiusOfRatio(visibility), dialogView)
     }
 
     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
         IndentingPrintWriter(pw, "  ").let {
             it.println("StatusBarWindowBlurController:")
             it.increaseIndent()
-            it.println("shadeBlurRadius: $shadeBlurRadius")
+            it.println("shadeRadius: ${shadeSpring.radius}")
+            it.println("globalActionsRadius: ${globalActionsSpring.radius}")
             it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
         }
     }
+
+    /**
+     * Animation helper that smoothly animates the depth using a spring and deals with frame
+     * invalidation.
+     */
+    inner class DepthAnimation() {
+        /**
+         * Blur radius visible on the UI, in pixels.
+         */
+        var radius = 0
+            private set
+
+        /**
+         * Radius that we're animating to.
+         */
+        private var pendingRadius = -1
+
+        /**
+         * View on {@link Surface} that wants depth.
+         */
+        private var view: View? = null
+
+        private var springAnimation = SpringAnimation(this, object :
+            FloatPropertyCompat<DepthAnimation>("blurRadius") {
+            override fun setValue(rect: DepthAnimation?, value: Float) {
+                radius = value.toInt()
+                scheduleUpdate(view)
+            }
+
+            override fun getValue(rect: DepthAnimation?): Float {
+                return radius.toFloat()
+            }
+        })
+
+        init {
+            springAnimation.spring = SpringForce(0.0f)
+            springAnimation.spring.dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
+            springAnimation.spring.stiffness = SpringForce.STIFFNESS_MEDIUM
+            springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
+        }
+
+        fun animateTo(newRadius: Int, viewToBlur: View? = null) {
+            if (pendingRadius == newRadius && view == viewToBlur) {
+                return
+            }
+            view = viewToBlur
+            pendingRadius = newRadius
+            springAnimation.animateToFinalPosition(newRadius.toFloat())
+        }
+
+        fun finishIfRunning() {
+            if (springAnimation.isRunning) {
+                springAnimation.skipToEnd()
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index c6d84ff..d2f781d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -651,7 +651,7 @@
      */
     public void updateNotifications(String reason) {
         reapplyFilterAndSort(reason);
-        if (mPresenter != null) {
+        if (mPresenter != null && !mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
             mPresenter.updateNotificationViews();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
index 0437877..cf670bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
@@ -142,9 +142,11 @@
         // To attach rows we can use _this one weird trick_: if the intended view to add does not
         // have a parent, then simply add it (and its children).
         entries.forEach { entry ->
-            val listItem = rowRegistry.requireView(entry)
+            // TODO: We should eventually map GroupEntry's themselves to views so that we don't
+            // depend on representativeEntry here which may actually be null in the future
+            val listItem = rowRegistry.requireView(entry.representativeEntry!!)
 
-            if (listItem.view.parent != null) {
+            if (listItem.view.parent == null) {
                 listContainer.addListItem(listItem)
                 stabilityManager.notifyViewAddition(listItem.view)
             }
@@ -153,7 +155,8 @@
                 for ((idx, childEntry) in entry.children.withIndex()) {
                     val childListItem = rowRegistry.requireView(childEntry)
                     // Child hasn't been added yet. add it!
-                    if (!listItem.notificationChildren.contains(childListItem)) {
+                    if (listItem.notificationChildren == null ||
+                            !listItem.notificationChildren.contains(childListItem)) {
                         // TODO: old code here just Log.wtf()'d here. This might wreak havoc
                         if (childListItem.view.parent != null) {
                             throw IllegalStateException("trying to add a notification child that " +
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 7019b5b..808e1b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -108,6 +108,12 @@
     /** If this notification was filtered out, then the filter that did the filtering. */
     @Nullable NotifFilter mExcludingFilter;
 
+    /**
+     * The NotifFilter, if any, that was active on this notification during the previous run of
+     * the list builder.
+     */
+    @Nullable NotifFilter mPreviousExcludingFilter;
+
     /** If this was a group child that was promoted to the top level, then who did the promoting. */
     @Nullable NotifPromoter mNotifPromoter;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index f7d6cef..19f7cef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -316,6 +316,7 @@
 
         // Step 7: Lock in our group structure and log anything that's changed since the last run
         mPipelineState.incrementTo(STATE_FINALIZING);
+        logFilterChanges();
         logParentingChanges();
         freeEmptyGroups();
 
@@ -363,6 +364,9 @@
             entry.setPreviousParent(entry.getParent());
             entry.setParent(null);
 
+            entry.mPreviousExcludingFilter = entry.mExcludingFilter;
+            entry.mExcludingFilter = null;
+
             if (entry.mFirstAddedIteration == -1) {
                 entry.mFirstAddedIteration = mIterationCount;
             }
@@ -371,8 +375,10 @@
         mNotifList.clear();
     }
 
-    private void filterNotifs(Collection<? extends ListEntry> entries,
-            List<ListEntry> out, List<NotifFilter> filters) {
+    private void filterNotifs(
+            Collection<? extends ListEntry> entries,
+            List<ListEntry> out,
+            List<NotifFilter> filters) {
         final long now = mSystemClock.uptimeMillis();
         for (ListEntry entry : entries)  {
             if (entry instanceof GroupEntry) {
@@ -585,8 +591,9 @@
      * filtered out during any of the filtering steps.
      */
     private void annulAddition(ListEntry entry) {
-        entry.setSection(-1);
-        entry.mNotifSection = null;
+        // TODO: We should null out the entry's section and promoter here. However, if we do that,
+        //  future runs will think that the section changed. We need a mPreviousNotifSection,
+        //  similar to what we do for parents.
         entry.setParent(null);
         if (entry.mFirstAddedIteration == mIterationCount) {
             entry.mFirstAddedIteration = -1;
@@ -615,6 +622,17 @@
         mGroups.values().removeIf(ge -> ge.getSummary() == null && ge.getChildren().isEmpty());
     }
 
+    private void logFilterChanges() {
+        for (NotificationEntry entry : mAllEntries) {
+            if (entry.mExcludingFilter != entry.mPreviousExcludingFilter) {
+                mLogger.logFilterChanged(
+                        entry.getKey(),
+                        entry.mPreviousExcludingFilter,
+                        entry.mExcludingFilter);
+            }
+        }
+    }
+
     private void logParentingChanges() {
         for (NotificationEntry entry : mAllEntries) {
             if (entry.getParent() != entry.getPreviousParent()) {
@@ -680,21 +698,8 @@
     };
 
     private boolean applyFilters(NotificationEntry entry, long now, List<NotifFilter> filters) {
-        NotifFilter filter = findRejectingFilter(entry, now, filters);
-
-        if (filter != entry.mExcludingFilter) {
-            mLogger.logFilterChanged(
-                    entry.getKey(),
-                    entry.mExcludingFilter != null ? entry.mExcludingFilter.getName() : null,
-                    filter != null ? filter.getName() : null);
-
-            // Note that groups and summaries can also be filtered out later if they're part of a
-            // malformed group. We currently don't have a great way to track that beyond parenting
-            // change logs. Consider adding something similar to mExcludingFilter for them.
-            entry.mExcludingFilter = filter;
-        }
-
-        return filter != null;
+        entry.mExcludingFilter = findRejectingFilter(entry, now, filters);
+        return entry.mExcludingFilter != null;
     }
 
     @Nullable private static NotifFilter findRejectingFilter(NotificationEntry entry, long now,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
new file mode 100644
index 0000000..261ae07
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import android.content.pm.UserInfo;
+import android.util.SparseArray;
+
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+
+/**
+ * A coordinator that filters out notifications for other users
+ *
+ * The NotifCollection contains the notifs for ALL users, so we need to remove any notifications
+ * that have been posted specifically to other users. Note that some system notifications are not
+ * posted to any particular user, and so must be shown to everyone.
+ *
+ * TODO: The NotificationLockscreenUserManager currently maintains the list of active user profiles.
+ *  We should spin that off into a standalone section at some point.
+ */
+public class HideNotifsForOtherUsersCoordinator implements Coordinator {
+    private final NotificationLockscreenUserManager mLockscreenUserManager;
+
+    @Inject
+    public HideNotifsForOtherUsersCoordinator(
+            NotificationLockscreenUserManager lockscreenUserManager) {
+        mLockscreenUserManager = lockscreenUserManager;
+    }
+
+    @Override
+    public void attach(NotifPipeline pipeline) {
+        pipeline.addPreGroupFilter(mFilter);
+        mLockscreenUserManager.addUserChangedListener(mUserChangedListener);
+    }
+
+    private final NotifFilter mFilter = new NotifFilter("NotCurrentUserFilter") {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            return !mLockscreenUserManager
+                    .isCurrentProfile(entry.getSbn().getUser().getIdentifier());
+        }
+    };
+
+    private final UserChangedListener mUserChangedListener = new UserChangedListener() {
+        @Override
+        public void onCurrentProfilesChanged(SparseArray<UserInfo> currentProfiles) {
+            mFilter.invalidateList();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
index aaf71f5..b773856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.java
@@ -95,11 +95,6 @@
         public boolean shouldFilterOut(NotificationEntry entry, long now) {
             final StatusBarNotification sbn = entry.getSbn();
 
-            // FILTER OUT the notification when the notification isn't for the current profile
-            if (!mLockscreenUserManager.isCurrentProfile(sbn.getUserId())) {
-                return true;
-            }
-
             // FILTER OUT the notification when the keyguard is showing and...
             if (mKeyguardStateController.isShowing()) {
                 // ... user settings or the device policy manager doesn't allow lockscreen
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 98104f8..03c0ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -49,15 +49,17 @@
     public NotifCoordinators(
             DumpManager dumpManager,
             FeatureFlags featureFlags,
-            HeadsUpCoordinator headsUpCoordinator,
+            HideNotifsForOtherUsersCoordinator hideNotifsForOtherUsersCoordinator,
             KeyguardCoordinator keyguardCoordinator,
             RankingCoordinator rankingCoordinator,
             ForegroundCoordinator foregroundCoordinator,
             DeviceProvisionedCoordinator deviceProvisionedCoordinator,
             BubbleCoordinator bubbleCoordinator,
+            HeadsUpCoordinator headsUpCoordinator,
             PreparationCoordinator preparationCoordinator) {
         dumpManager.registerDumpable(TAG, this);
         mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
+        mCoordinators.add(hideNotifsForOtherUsersCoordinator);
         mCoordinators.add(keyguardCoordinator);
         mCoordinators.add(rankingCoordinator);
         mCoordinators.add(foregroundCoordinator);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
index 7e9e760..e9cbf32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinator.java
@@ -45,7 +45,8 @@
     public void attach(NotifPipeline pipeline) {
         mStatusBarStateController.addCallback(mStatusBarStateCallback);
 
-        pipeline.addPreGroupFilter(mNotifFilter);
+        pipeline.addPreGroupFilter(mSuspendedFilter);
+        pipeline.addPreGroupFilter(mDozingFilter);
     }
 
     /**
@@ -53,33 +54,30 @@
      * NotifListBuilder invalidates the notification list each time the ranking is updated,
      * so we don't need to explicitly invalidate this filter on ranking update.
      */
-    private final NotifFilter mNotifFilter = new NotifFilter(TAG) {
+    private final NotifFilter mSuspendedFilter = new NotifFilter("IsSuspendedFilter") {
         @Override
         public boolean shouldFilterOut(NotificationEntry entry, long now) {
-            // App suspended from Ranking
-            if (entry.getRanking().isSuspended()) {
-                return true;
-            }
+            return entry.getRanking().isSuspended();
+        }
+    };
 
+    private final NotifFilter mDozingFilter = new NotifFilter("IsDozingFilter") {
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
             // Dozing + DND Settings from Ranking object
             if (mStatusBarStateController.isDozing() && entry.shouldSuppressAmbient()) {
                 return true;
             }
 
-            if (!mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList()) {
-                return true;
-            }
-
-            return false;
+            return !mStatusBarStateController.isDozing() && entry.shouldSuppressNotificationList();
         }
     };
 
-
     private final StatusBarStateController.StateListener mStatusBarStateCallback =
             new StatusBarStateController.StateListener() {
                 @Override
                 public void onDozingChanged(boolean isDozing) {
-                    mNotifFilter.invalidateList();
+                    mDozingFilter.invalidateList();
                 }
             };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index 763547c..e946cf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.log.dagger.NotificationLog
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import javax.inject.Inject
 
 class ShadeListBuilderLogger @Inject constructor(
@@ -126,13 +127,13 @@
 
     fun logFilterChanged(
         key: String,
-        prevFilter: String?,
-        newFilter: String?
+        prevFilter: NotifFilter?,
+        newFilter: NotifFilter?
     ) {
         buffer.log(TAG, INFO, {
             str1 = key
-            str2 = prevFilter
-            str3 = newFilter
+            str2 = prevFilter?.name
+            str3 = newFilter?.name
         }, {
             "Filter changed for $str1: $str2 -> $str3"
         })
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index be8af82..823b186 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -6478,7 +6478,7 @@
 
     private boolean hasActiveNotifications() {
         if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
-            return mNotifPipeline.getShadeList().isEmpty();
+            return !mNotifPipeline.getShadeList().isEmpty();
         } else {
             return mEntryManager.hasActiveNotifications();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
index adca10f..ecfe116 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java
@@ -110,10 +110,14 @@
     private final float mTouchSlop;
     // Duration after which we consider the event as longpress.
     private final int mLongPressTimeout;
+    // The back gesture type
+    private int mBackType;
 
     private final PointF mDownPoint = new PointF();
+    private final PointF mEndPoint = new PointF();
     private boolean mThresholdCrossed = false;
     private boolean mAllowGesture = false;
+    private boolean mLogGesture = false;
     private boolean mInRejectedExclusion = false;
     private boolean mIsOnLeftEdge;
 
@@ -141,24 +145,16 @@
 
                     mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x,
                             (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
-                    int backtype = (mInRejectedExclusion
-                            ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED :
-                            SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED);
-                    SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
-                            (int) mDownPoint.y, mIsOnLeftEdge
-                                    ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
-                                    SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
+                    logGesture(mInRejectedExclusion
+                            ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED
+                            : SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED);
                 }
 
                 @Override
                 public void cancelBack() {
+                    logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE);
                     mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
                             (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
-                    int backtype = SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE;
-                    SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype,
-                            (int) mDownPoint.y, mIsOnLeftEdge
-                                    ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
-                                    SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
                 }
             };
 
@@ -331,39 +327,55 @@
     }
 
     private boolean isWithinTouchRegion(int x, int y) {
-        // Disallow if too far from the edge
-        if (x > mEdgeWidthLeft + mLeftInset
-                && x < (mDisplaySize.x - mEdgeWidthRight - mRightInset)) {
-            return false;
-        }
-
         // Disallow if we are in the bottom gesture area
         if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
             return false;
         }
 
-        // Always allow if the user is in a transient sticky immersive state
-        if (mIsNavBarShownTransiently) {
-            return true;
+        // If the point is way too far (twice the margin), it is
+        // not interesting to us for logging purposes, nor we
+        // should process it.  Simply return false and keep
+        // mLogGesture = false.
+        if (x > 2 * (mEdgeWidthLeft + mLeftInset)
+                && x < (mDisplaySize.x - 2 * (mEdgeWidthRight + mRightInset))) {
+            return false;
         }
 
-        boolean isInExcludedRegion = mExcludeRegion.contains(x, y);
-        if (isInExcludedRegion) {
-            mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1,
-                    false /* isButton */, !mIsOnLeftEdge);
-            SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED,
-                    SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y,
-                    mIsOnLeftEdge ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT :
-                            SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT);
-        } else {
-            mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
+        // Denotes whether we should proceed with the gesture.
+        // Even if it is false, we may want to log it assuming
+        // it is not invalid due to exclusion.
+        boolean withinRange = x <= mEdgeWidthLeft + mLeftInset
+                || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset);
+
+        // Always allow if the user is in a transient sticky immersive state
+        if (mIsNavBarShownTransiently) {
+            mLogGesture = true;
+            return withinRange;
         }
-        return !isInExcludedRegion;
+
+        if (mExcludeRegion.contains(x, y)) {
+            if (withinRange) {
+                // Log as exclusion only if it is in acceptable range in the first place.
+                mOverviewProxyService.notifyBackAction(
+                        false /* completed */, -1, -1, false /* isButton */, !mIsOnLeftEdge);
+                // We don't have the end point for logging purposes.
+                mEndPoint.x = -1;
+                mEndPoint.y = -1;
+                mLogGesture = true;
+                logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED);
+            }
+            return false;
+        }
+
+        mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y);
+        mLogGesture = true;
+        return withinRange;
     }
 
     private void cancelGesture(MotionEvent ev) {
         // Send action cancel to reset all the touch events
         mAllowGesture = false;
+        mLogGesture = false;
         mInRejectedExclusion = false;
         MotionEvent cancelEv = MotionEvent.obtain(ev);
         cancelEv.setAction(MotionEvent.ACTION_CANCEL);
@@ -371,51 +383,86 @@
         cancelEv.recycle();
     }
 
+    private void logGesture(int backType) {
+        if (!mLogGesture) {
+            return;
+        }
+        mLogGesture = false;
+        SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backType,
+                (int) mDownPoint.y, mIsOnLeftEdge
+                        ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT
+                        : SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT,
+                (int) mDownPoint.x, (int) mDownPoint.y,
+                (int) mEndPoint.x, (int) mEndPoint.y,
+                mEdgeWidthLeft + mLeftInset,
+                mDisplaySize.x - (mEdgeWidthRight + mRightInset));
+    }
+
     private void onMotionEvent(MotionEvent ev) {
         int action = ev.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
             // Verify if this is in within the touch region and we aren't in immersive mode, and
             // either the bouncer is showing or the notification panel is hidden
             mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset;
+            mLogGesture = false;
             mInRejectedExclusion = false;
             mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags)
                     && isWithinTouchRegion((int) ev.getX(), (int) ev.getY());
             if (mAllowGesture) {
                 mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge);
                 mEdgeBackPlugin.onMotionEvent(ev);
-
+            }
+            if (mLogGesture) {
                 mDownPoint.set(ev.getX(), ev.getY());
+                mEndPoint.set(-1, -1);
                 mThresholdCrossed = false;
             }
-
-        } else if (mAllowGesture) {
+        } else if (mAllowGesture || mLogGesture) {
             if (!mThresholdCrossed) {
+                mEndPoint.x = (int) ev.getX();
+                mEndPoint.y = (int) ev.getY();
                 if (action == MotionEvent.ACTION_POINTER_DOWN) {
-                    // We do not support multi touch for back gesture
-                    cancelGesture(ev);
+                    if (mAllowGesture) {
+                        logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH);
+                        // We do not support multi touch for back gesture
+                        cancelGesture(ev);
+                    }
+                    mLogGesture = false;
                     return;
                 } else if (action == MotionEvent.ACTION_MOVE) {
                     if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) {
-                        cancelGesture(ev);
+                        if (mAllowGesture) {
+                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS);
+                            cancelGesture(ev);
+                        }
+                        mLogGesture = false;
                         return;
                     }
                     float dx = Math.abs(ev.getX() - mDownPoint.x);
                     float dy = Math.abs(ev.getY() - mDownPoint.y);
                     if (dy > dx && dy > mTouchSlop) {
-                        cancelGesture(ev);
+                        if (mAllowGesture) {
+                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_VERTICAL_MOVE);
+                            cancelGesture(ev);
+                        }
+                        mLogGesture = false;
                         return;
-
                     } else if (dx > dy && dx > mTouchSlop) {
-                        mThresholdCrossed = true;
-                        // Capture inputs
-                        mInputMonitor.pilferPointers();
+                        if (mAllowGesture) {
+                            mThresholdCrossed = true;
+                            // Capture inputs
+                            mInputMonitor.pilferPointers();
+                        } else {
+                            logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE);
+                        }
                     }
                 }
-
             }
 
-            // forward touch
-            mEdgeBackPlugin.onMotionEvent(ev);
+            if (mAllowGesture) {
+                // forward touch
+                mEdgeBackPlugin.onMotionEvent(ev);
+            }
         }
 
         Dependency.get(ProtoTracer.class).update();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index cf9d43e..d70484e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
 import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -30,241 +28,98 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.AttributeSet;
-import android.view.ViewTreeObserver;
-import android.view.accessibility.AccessibilityNodeInfo;
+import android.util.SparseArray;
+import android.view.ViewTreeObserver.OnPreDrawListener;
 
 import com.android.internal.graphics.ColorUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.phone.ScrimController.ScrimVisibility;
-import com.android.systemui.statusbar.policy.AccessibilityController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
 /**
  * Manages the different states and animations of the unlock icon.
  */
-public class LockIcon extends KeyguardAffordanceView implements
-        ViewTreeObserver.OnPreDrawListener {
+public class LockIcon extends KeyguardAffordanceView {
 
-    private static final int STATE_LOCKED = 0;
-    private static final int STATE_LOCK_OPEN = 1;
-    private static final int STATE_SCANNING_FACE = 2;
-    private static final int STATE_BIOMETRICS_ERROR = 3;
-    private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private final AccessibilityController mAccessibilityController;
-    private final KeyguardStateController mKeyguardStateController;
-    private final KeyguardBypassController mBypassController;
-    private final NotificationWakeUpCoordinator mWakeUpCoordinator;
-    private final HeadsUpManagerPhone mHeadsUpManager;
-
-    private int mLastState = 0;
-    private boolean mForceUpdate;
-    private boolean mTransientBiometricsError;
-    private boolean mIsFaceUnlockState;
-    private boolean mSimLocked;
-    private int mDensity;
+    static final int STATE_LOCKED = 0;
+    static final int STATE_LOCK_OPEN = 1;
+    static final int STATE_SCANNING_FACE = 2;
+    static final int STATE_BIOMETRICS_ERROR = 3;
+    private float mDozeAmount;
+    private int mIconColor;
+    private StateProvider mStateProvider;
+    private int mOldState;
     private boolean mPulsing;
     private boolean mDozing;
-    private boolean mDocked;
-    private boolean mBlockUpdates;
-    private int mIconColor;
-    private float mDozeAmount;
-    private boolean mBouncerShowingScrimmed;
-    private boolean mWakeAndUnlockRunning;
-    private boolean mKeyguardShowing;
-    private boolean mShowingLaunchAffordance;
     private boolean mKeyguardJustShown;
-    private boolean mUpdatePending;
-    private boolean mBouncerPreHideAnimation;
-    private int mStatusBarState = StatusBarState.SHADE;
+    private final SparseArray<Drawable> mDrawableCache = new SparseArray<>();
 
-    private final KeyguardStateController.Callback mKeyguardMonitorCallback =
-            new KeyguardStateController.Callback() {
-                @Override
-                public void onKeyguardShowingChanged() {
-                    boolean force = false;
-                    boolean wasShowing = mKeyguardShowing;
-                    mKeyguardShowing = mKeyguardStateController.isShowing();
-                    if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
-                        mBlockUpdates = false;
-                        force = true;
-                    }
-                    if (!wasShowing && mKeyguardShowing) {
-                        mKeyguardJustShown = true;
-                    }
-                    update(force);
-                }
+    private final OnPreDrawListener mOnPreDrawListener = new OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            getViewTreeObserver().removeOnPreDrawListener(this);
 
-                @Override
-                public void onKeyguardFadingAwayChanged() {
-                    if (!mKeyguardStateController.isKeyguardFadingAway()) {
-                        mBouncerPreHideAnimation = false;
-                        if (mBlockUpdates) {
-                            mBlockUpdates = false;
-                            update(true /* force */);
-                        }
-                    }
-                }
+            int newState = mStateProvider.getState();
+            Drawable icon = getIcon(newState);
+            setImageDrawable(icon, false);
 
-                @Override
-                public void onUnlockedChanged() {
-                    update();
-                }
-            };
+            if (newState == STATE_SCANNING_FACE) {
+                announceForAccessibility(getResources().getString(
+                        R.string.accessibility_scanning_face));
+            }
 
-    @Inject
-    public LockIcon(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
-            AccessibilityController accessibilityController,
-            KeyguardBypassController bypassController,
-            NotificationWakeUpCoordinator wakeUpCoordinator,
-            KeyguardStateController keyguardStateController,
-            HeadsUpManagerPhone headsUpManager) {
+            if (icon instanceof AnimatedVectorDrawable) {
+                final AnimatedVectorDrawable animation = (AnimatedVectorDrawable) icon;
+                animation.forceAnimationOnUI();
+                animation.clearAnimationCallbacks();
+                animation.registerAnimationCallback(
+                        new Animatable2.AnimationCallback() {
+                            @Override
+                            public void onAnimationEnd(Drawable drawable) {
+                                if (getDrawable() == animation
+                                        && newState == mStateProvider.getState()
+                                        && newState == STATE_SCANNING_FACE) {
+                                    animation.start();
+                                } else {
+                                    Trace.endAsyncSection("LockIcon#Animation", newState);
+                                }
+                            }
+                        });
+                Trace.beginAsyncSection("LockIcon#Animation", newState);
+                animation.start();
+            }
+
+            return true;
+        }
+    };
+
+    public LockIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mContext = context;
-        mKeyguardUpdateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
-        mAccessibilityController = accessibilityController;
-        mBypassController = bypassController;
-        mWakeUpCoordinator = wakeUpCoordinator;
-        mKeyguardStateController = keyguardStateController;
-        mHeadsUpManager = headsUpManager;
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
-        mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
-        update();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
-    }
-
-    /**
-     * If we're currently presenting an authentication error message.
-     */
-    public void setTransientBiometricsError(boolean transientBiometricsError) {
-        mTransientBiometricsError = transientBiometricsError;
-        update();
+    void setStateProvider(StateProvider stateProvider) {
+        mStateProvider = stateProvider;
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        final int density = newConfig.densityDpi;
-        if (density != mDensity) {
-            mDensity = density;
-            update();
-        }
-    }
-
-    public void update() {
-        update(false /* force */);
-    }
-
-    public void update(boolean force) {
-        if (force) {
-            mForceUpdate = true;
-        }
-        if (!mUpdatePending) {
-            mUpdatePending = true;
-            getViewTreeObserver().addOnPreDrawListener(this);
-        }
-    }
-
-    @Override
-    public boolean onPreDraw() {
-        mUpdatePending = false;
-        getViewTreeObserver().removeOnPreDrawListener(this);
-
-        int state = getState();
-        int lastState = mLastState;
-        boolean keyguardJustShown = mKeyguardJustShown;
-        mIsFaceUnlockState = state == STATE_SCANNING_FACE;
-        mLastState = state;
-        mKeyguardJustShown = false;
-
-        boolean shouldUpdate = lastState != state || mForceUpdate;
-        if (mBlockUpdates && canBlockUpdates()) {
-            shouldUpdate = false;
-        }
-        if (shouldUpdate) {
-            mForceUpdate = false;
-            @LockAnimIndex final int lockAnimIndex = getAnimationIndexForTransition(lastState,
-                    state, mPulsing, mDozing, keyguardJustShown);
-            boolean isAnim = lockAnimIndex != -1;
-            int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(state);
-
-            Drawable icon = mContext.getDrawable(iconRes);
-            final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
-                    ? (AnimatedVectorDrawable) icon
-                    : null;
-            setImageDrawable(icon, false);
-            if (mIsFaceUnlockState) {
-                announceForAccessibility(getContext().getString(
-                        R.string.accessibility_scanning_face));
-            }
-
-            if (animation != null && isAnim) {
-                animation.forceAnimationOnUI();
-                animation.clearAnimationCallbacks();
-                animation.registerAnimationCallback(new Animatable2.AnimationCallback() {
-                    @Override
-                    public void onAnimationEnd(Drawable drawable) {
-                        if (getDrawable() == animation && state == getState()
-                                && doesAnimationLoop(lockAnimIndex)) {
-                            animation.start();
-                        } else {
-                            Trace.endAsyncSection("LockIcon#Animation", state);
-                        }
-                    }
-                });
-                Trace.beginAsyncSection("LockIcon#Animation", state);
-                animation.start();
-            }
-        }
-        updateDarkTint();
-
-        updateIconVisibility();
-        updateClickability();
-
-        return true;
+        mDrawableCache.clear();
     }
 
     /**
      * Update the icon visibility
      * @return true if the visibility changed
      */
-    boolean updateIconVisibility() {
-        boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
-        boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
-                || mShowingLaunchAffordance;
-        if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
-            if ((mHeadsUpManager.isHeadsUpGoingAway() || mHeadsUpManager.hasPinnedHeadsUp()
-                    || mStatusBarState == StatusBarState.KEYGUARD)
-                    && !mWakeUpCoordinator.getNotificationsFullyHidden()) {
-                invisible = true;
-            }
-        }
-        boolean wasInvisible = getVisibility() == INVISIBLE;
-        if (invisible != wasInvisible) {
-            setVisibility(invisible ? INVISIBLE : VISIBLE);
+    boolean updateIconVisibility(boolean visible) {
+        boolean wasVisible = getVisibility() == VISIBLE;
+        if (visible != wasVisible) {
+            setVisibility(visible ? VISIBLE : INVISIBLE);
             animate().cancel();
-            if (!invisible) {
+            if (visible) {
                 setScaleX(0);
                 setScaleY(0);
                 animate()
@@ -280,49 +135,47 @@
         return false;
     }
 
-    private boolean canBlockUpdates() {
-        return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
+    void update(int oldState, boolean pulsing, boolean dozing, boolean keyguardJustShown) {
+        mOldState = oldState;
+        mPulsing = pulsing;
+        mDozing = dozing;
+        mKeyguardJustShown = keyguardJustShown;
+
+        getViewTreeObserver().addOnPreDrawListener(mOnPreDrawListener);
     }
 
-    private void updateClickability() {
-        if (mAccessibilityController == null) {
-            return;
+    void setDozeAmount(float dozeAmount) {
+        mDozeAmount = dozeAmount;
+        updateDarkTint();
+    }
+
+    void onThemeChange(int iconColor) {
+        mDrawableCache.clear();
+        mIconColor = iconColor;
+        updateDarkTint();
+    }
+
+    private void updateDarkTint() {
+        int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
+        setImageTintList(ColorStateList.valueOf(color));
+    }
+
+    private Drawable getIcon(int newState) {
+        @LockAnimIndex final int lockAnimIndex =
+                getAnimationIndexForTransition(mOldState, newState, mPulsing, mDozing,
+                        mKeyguardJustShown);
+
+        boolean isAnim = lockAnimIndex != -1;
+        int iconRes = isAnim ? getThemedAnimationResId(lockAnimIndex) : getIconForState(newState);
+
+        if (!mDrawableCache.contains(iconRes)) {
+            mDrawableCache.put(iconRes, getResources().getDrawable(iconRes));
         }
-        boolean canLock = mKeyguardStateController.isMethodSecure()
-                && mKeyguardStateController.canDismissLockScreen();
-        boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
-        setClickable(clickToUnlock);
-        setLongClickable(canLock && !clickToUnlock);
-        setFocusable(mAccessibilityController.isAccessibilityEnabled());
+
+        return mDrawableCache.get(iconRes);
     }
 
-    @Override
-    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-        super.onInitializeAccessibilityNodeInfo(info);
-        boolean fingerprintRunning = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
-        // Only checking if unlocking with Biometric is allowed (no matter strong or non-strong
-        // as long as primary auth, i.e. PIN/pattern/password, is not required), so it's ok to
-        // pass true for isStrongBiometric to isUnlockingWithBiometricAllowed() to bypass the
-        // check of whether non-strong biometric is allowed
-        boolean unlockingAllowed = mKeyguardUpdateMonitor
-                        .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
-        if (fingerprintRunning && unlockingAllowed) {
-            AccessibilityNodeInfo.AccessibilityAction unlock
-                    = new AccessibilityNodeInfo.AccessibilityAction(
-                    AccessibilityNodeInfo.ACTION_CLICK,
-                    getContext().getString(R.string.accessibility_unlock_without_fingerprint));
-            info.addAction(unlock);
-            info.setHintText(getContext().getString(
-                    R.string.accessibility_waiting_for_fingerprint));
-        } else if (mIsFaceUnlockState) {
-            //Avoid 'button' to be spoken for scanning face
-            info.setClassName(LockIcon.class.getName());
-            info.setContentDescription(getContext().getString(
-                R.string.accessibility_scanning_face));
-        }
-    }
-
-    private int getIconForState(int state) {
+    static int getIconForState(int state) {
         int iconRes;
         switch (state) {
             case STATE_LOCKED:
@@ -343,11 +196,7 @@
         return iconRes;
     }
 
-    private boolean doesAnimationLoop(@LockAnimIndex int lockAnimIndex) {
-        return lockAnimIndex == SCANNING;
-    }
-
-    private static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
+    static int getAnimationIndexForTransition(int oldState, int newState, boolean pulsing,
             boolean dozing, boolean keyguardJustShown) {
 
         // Never animate when screen is off
@@ -367,42 +216,10 @@
         return -1;
     }
 
-    public void setBouncerShowingScrimmed(boolean bouncerShowing) {
-        mBouncerShowingScrimmed = bouncerShowing;
-        if (mBypassController.getBypassEnabled()) {
-            update();
-        }
-    }
-
-    /**
-     * Animate padlock opening when bouncer challenge is solved.
-     */
-    public void onBouncerPreHideAnimation() {
-        mBouncerPreHideAnimation = true;
-        update();
-    }
-
-    void setIconColor(int iconColor) {
-        mIconColor = iconColor;
-        updateDarkTint();
-    }
-
-    void setSimLocked(boolean simLocked) {
-        mSimLocked = simLocked;
-    }
-
-    /** Set if the device is docked. */
-    public void setDocked(boolean docked) {
-        if (mDocked != docked) {
-            mDocked = docked;
-            update();
-        }
-    }
-
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({ERROR, UNLOCK, LOCK, SCANNING})
     @interface LockAnimIndex {}
-    private static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
+    static final int ERROR = 0, UNLOCK = 1, LOCK = 2, SCANNING = 3;
     private static final int[][] LOCK_ANIM_RES_IDS = new int[][] {
             {
                     R.anim.lock_to_error,
@@ -433,7 +250,7 @@
     private int getThemedAnimationResId(@LockAnimIndex int lockAnimIndex) {
         final String setting = TextUtils.emptyIfNull(
                 Settings.Secure.getString(getContext().getContentResolver(),
-                Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
+                        Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES));
         if (setting.contains("com.android.theme.icon_pack.circular.android")) {
             return LOCK_ANIM_RES_IDS[1][lockAnimIndex];
         } else if (setting.contains("com.android.theme.icon_pack.filled.android")) {
@@ -444,83 +261,8 @@
         return LOCK_ANIM_RES_IDS[0][lockAnimIndex];
     }
 
-    private int getState() {
-        KeyguardUpdateMonitor updateMonitor = Dependency.get(KeyguardUpdateMonitor.class);
-        if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
-                || mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
-            return STATE_LOCK_OPEN;
-        } else if (mTransientBiometricsError) {
-            return STATE_BIOMETRICS_ERROR;
-        } else if (updateMonitor.isFaceDetectionRunning() && !mPulsing) {
-            return STATE_SCANNING_FACE;
-        } else {
-            return STATE_LOCKED;
-        }
+    interface StateProvider {
+        int getState();
     }
 
-    /**
-     * When keyguard is in pulsing (AOD2) state.
-     * @param pulsing {@code true} when pulsing.
-     */
-    public void setPulsing(boolean pulsing) {
-        mPulsing = pulsing;
-        update();
-    }
-
-    private void updateDarkTint() {
-        int color = ColorUtils.blendARGB(mIconColor, Color.WHITE, mDozeAmount);
-        setImageTintList(ColorStateList.valueOf(color));
-    }
-
-    /**
-     * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
-     * icon on top of the black front scrim.
-     * @param wakeAndUnlock are we wake and unlocking
-     * @param isUnlock are we currently unlocking
-     */
-    public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
-        if (wakeAndUnlock) {
-            mWakeAndUnlockRunning = true;
-        }
-        if (isUnlock && mBypassController.getBypassEnabled() && canBlockUpdates()) {
-            // We don't want the icon to change while we are unlocking
-            mBlockUpdates = true;
-        }
-        update();
-    }
-
-    /**
-     * When we're launching an affordance, like double pressing power to open camera.
-     */
-    public void onShowingLaunchAffordanceChanged(boolean showing) {
-        mShowingLaunchAffordance = showing;
-        update();
-    }
-
-    /**
-     * Called whenever the scrims become opaque, transparent or semi-transparent.
-     */
-    public void onScrimVisibilityChanged(@ScrimVisibility int scrimsVisible) {
-        if (mWakeAndUnlockRunning
-                && scrimsVisible == ScrimController.TRANSPARENT) {
-            mWakeAndUnlockRunning = false;
-            update();
-        }
-    }
-
-    void setDozing(boolean dozing) {
-        mDozing = dozing;
-        update();
-    }
-
-    void setDozeAmount(float dozeAmount) {
-        mDozeAmount = dozeAmount;
-        updateDarkTint();
-    }
-
-    /** Set the StatusBarState. */
-    public void setStatusBarState(int statusBarState) {
-        mStatusBarState = statusBarState;
-        updateIconVisibility();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 2b1a8a4..f7c861b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -16,11 +16,19 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_BIOMETRICS_ERROR;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCKED;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_LOCK_OPEN;
+import static com.android.systemui.statusbar.phone.LockIcon.STATE_SCANNING_FACE;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricSourceType;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 
 import androidx.annotation.Nullable;
 
@@ -29,15 +37,18 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import java.util.Optional;
 
@@ -59,6 +70,21 @@
     private final NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
     private final KeyguardBypassController mKeyguardBypassController;
     private final Optional<DockManager> mDockManager;
+    private final KeyguardStateController mKeyguardStateController;
+    private final Resources mResources;
+    private final HeadsUpManagerPhone mHeadsUpManagerPhone;
+    private boolean mKeyguardShowing;
+    private boolean mKeyguardJustShown;
+    private boolean mBlockUpdates;
+    private boolean mPulsing;
+    private boolean mDozing;
+    private boolean mSimLocked;
+    private boolean mTransientBiometricsError;
+    private boolean mDocked;
+    private boolean mWakeAndUnlockRunning;
+    private boolean mShowingLaunchAffordance;
+    private boolean mBouncerShowingScrimmed;
+    private int mStatusBarState = StatusBarState.SHADE;
     private LockIcon mLockIcon;
 
     private View.OnAttachStateChangeListener mOnAttachStateChangeListener =
@@ -69,10 +95,13 @@
             mConfigurationController.addCallback(mConfigurationListener);
             mNotificationWakeUpCoordinator.addListener(mWakeUpListener);
             mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback);
+            mKeyguardStateController.addCallback(mKeyguardMonitorCallback);
 
             mDockManager.ifPresent(dockManager -> dockManager.addListener(mDockEventListener));
 
+            mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
             mConfigurationListener.onThemeChanged();
+            update();
         }
 
         @Override
@@ -81,7 +110,7 @@
             mConfigurationController.removeCallback(mConfigurationListener);
             mNotificationWakeUpCoordinator.removeListener(mWakeUpListener);
             mKeyguardUpdateMonitor.removeCallback(mUpdateMonitorCallback);
-
+            mKeyguardStateController.removeCallback(mKeyguardMonitorCallback);
 
             mDockManager.ifPresent(dockManager -> dockManager.removeListener(mDockEventListener));
         }
@@ -91,32 +120,44 @@
             new StatusBarStateController.StateListener() {
                 @Override
                 public void onDozingChanged(boolean isDozing) {
-                    mLockIcon.setDozing(isDozing);
+                    setDozing(isDozing);
                 }
 
                 @Override
                 public void onDozeAmountChanged(float linear, float eased) {
-                    mLockIcon.setDozeAmount(eased);
+                    if (mLockIcon != null) {
+                        mLockIcon.setDozeAmount(eased);
+                    }
                 }
 
                 @Override
                 public void onStateChanged(int newState) {
-                    mLockIcon.setStatusBarState(newState);
+                    setStatusBarState(newState);
                 }
             };
 
     private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
+        private int mDensity;
+
         @Override
         public void onThemeChanged() {
+            if (mLockIcon == null) {
+                return;
+            }
+
             TypedArray typedArray = mLockIcon.getContext().getTheme().obtainStyledAttributes(
                     null, new int[]{ R.attr.wallpaperTextColor }, 0, 0);
             int iconColor = typedArray.getColor(0, Color.WHITE);
             typedArray.recycle();
-            mLockIcon.setIconColor(iconColor);
+            mLockIcon.onThemeChange(iconColor);
         }
 
         @Override
         public void onDensityOrFontScaleChanged() {
+            if (mLockIcon == null) {
+                return;
+            }
+
             ViewGroup.LayoutParams lp = mLockIcon.getLayoutParams();
             if (lp == null) {
                 return;
@@ -125,24 +166,41 @@
             lp.height = mLockIcon.getResources().getDimensionPixelSize(
                     R.dimen.keyguard_lock_height);
             mLockIcon.setLayoutParams(lp);
-            mLockIcon.update(true /* force */);
+            update(true /* force */);
         }
 
         @Override
         public void onLocaleListChanged() {
+            if (mLockIcon == null) {
+                return;
+            }
+
             mLockIcon.setContentDescription(
                     mLockIcon.getResources().getText(R.string.accessibility_unlock_button));
-            mLockIcon.update(true /* force */);
+            update(true /* force */);
+        }
+
+        @Override
+        public void onConfigChanged(Configuration newConfig) {
+            final int density = newConfig.densityDpi;
+            if (density != mDensity) {
+                mDensity = density;
+                update();
+            }
         }
     };
 
     private final WakeUpListener mWakeUpListener = new WakeUpListener() {
         @Override
+        public void onPulseExpansionChanged(boolean expandingChanged) {
+        }
+
+        @Override
         public void onFullyHiddenChanged(boolean isFullyHidden) {
             if (mKeyguardBypassController.getBypassEnabled()) {
-                boolean changed = mLockIcon.updateIconVisibility();
+                boolean changed = updateIconVisibility();
                 if (changed) {
-                    mLockIcon.update();
+                    update();
                 }
             }
         }
@@ -152,30 +210,103 @@
             new KeyguardUpdateMonitorCallback() {
                 @Override
                 public void onSimStateChanged(int subId, int slotId, int simState) {
-                    mLockIcon.setSimLocked(mKeyguardUpdateMonitor.isSimPinSecure());
-                    mLockIcon.update();
+                    mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
+                    update();
                 }
 
                 @Override
                 public void onKeyguardVisibilityChanged(boolean showing) {
-                    mLockIcon.update();
+                    update();
                 }
 
                 @Override
                 public void onBiometricRunningStateChanged(boolean running,
                         BiometricSourceType biometricSourceType) {
-                    mLockIcon.update();
+                    update();
                 }
 
                 @Override
                 public void onStrongAuthStateChanged(int userId) {
-                    mLockIcon.update();
+                    update();
                 }
             };
 
     private final DockManager.DockEventListener mDockEventListener =
-            event -> mLockIcon.setDocked(event == DockManager.STATE_DOCKED
-                    || event == DockManager.STATE_DOCKED_HIDE);
+            event -> {
+                boolean docked =
+                        event == DockManager.STATE_DOCKED || event == DockManager.STATE_DOCKED_HIDE;
+                if (docked != mDocked) {
+                    mDocked = docked;
+                    update();
+                }
+            };
+
+    private final KeyguardStateController.Callback mKeyguardMonitorCallback =
+            new KeyguardStateController.Callback() {
+                @Override
+                public void onKeyguardShowingChanged() {
+                    boolean force = false;
+                    boolean wasShowing = mKeyguardShowing;
+                    mKeyguardShowing = mKeyguardStateController.isShowing();
+                    if (!wasShowing && mKeyguardShowing && mBlockUpdates) {
+                        mBlockUpdates = false;
+                        force = true;
+                    }
+                    if (!wasShowing && mKeyguardShowing) {
+                        mKeyguardJustShown = true;
+                    }
+                    update(force);
+                }
+
+                @Override
+                public void onKeyguardFadingAwayChanged() {
+                    if (!mKeyguardStateController.isKeyguardFadingAway()) {
+                        if (mBlockUpdates) {
+                            mBlockUpdates = false;
+                            update(true /* force */);
+                        }
+                    }
+                }
+
+                @Override
+                public void onUnlockedChanged() {
+                    update();
+                }
+            };
+
+    private final View.AccessibilityDelegate mAccessibilityDelegate =
+            new View.AccessibilityDelegate() {
+                @Override
+                public void onInitializeAccessibilityNodeInfo(View host,
+                        AccessibilityNodeInfo info) {
+                    super.onInitializeAccessibilityNodeInfo(host, info);
+                    boolean fingerprintRunning =
+                            mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
+                    // Only checking if unlocking with Biometric is allowed (no matter strong or
+                    // non-strong as long as primary auth, i.e. PIN/pattern/password, is not
+                    // required), so it's ok to pass true for isStrongBiometric to
+                    // isUnlockingWithBiometricAllowed() to bypass the check of whether non-strong
+                    // biometric is allowed
+                    boolean unlockingAllowed = mKeyguardUpdateMonitor
+                            .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */);
+                    if (fingerprintRunning && unlockingAllowed) {
+                        AccessibilityNodeInfo.AccessibilityAction unlock =
+                                new AccessibilityNodeInfo.AccessibilityAction(
+                                AccessibilityNodeInfo.ACTION_CLICK,
+                                mResources.getString(
+                                        R.string.accessibility_unlock_without_fingerprint));
+                        info.addAction(unlock);
+                        info.setHintText(mResources.getString(
+                                R.string.accessibility_waiting_for_fingerprint));
+                    } else if (getState() == STATE_SCANNING_FACE) {
+                        //Avoid 'button' to be spoken for scanning face
+                        info.setClassName(LockIcon.class.getName());
+                        info.setContentDescription(mResources.getString(
+                                R.string.accessibility_scanning_face));
+                    }
+                }
+            };
+    private int mLastState;
 
     @Inject
     public LockscreenLockIconController(LockscreenGestureLogger lockscreenGestureLogger,
@@ -188,7 +319,10 @@
             ConfigurationController configurationController,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             KeyguardBypassController keyguardBypassController,
-            @Nullable DockManager dockManager) {
+            @Nullable DockManager dockManager,
+            KeyguardStateController keyguardStateController,
+            @Main Resources resources,
+            HeadsUpManagerPhone headsUpManagerPhone) {
         mLockscreenGestureLogger = lockscreenGestureLogger;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
@@ -200,24 +334,31 @@
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mKeyguardBypassController = keyguardBypassController;
         mDockManager = dockManager == null ? Optional.empty() : Optional.of(dockManager);
+        mKeyguardStateController = keyguardStateController;
+        mResources = resources;
+        mHeadsUpManagerPhone = headsUpManagerPhone;
 
         mKeyguardIndicationController.setLockIconController(this);
     }
 
     /**
      * Associate the controller with a {@link LockIcon}
+     *
+     * TODO: change to an init method and inject the view.
      */
     public void attach(LockIcon lockIcon) {
         mLockIcon = lockIcon;
 
         mLockIcon.setOnClickListener(this::handleClick);
         mLockIcon.setOnLongClickListener(this::handleLongClick);
+        mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate);
+        mLockIcon.setStateProvider(this::getState);
 
         if (mLockIcon.isAttachedToWindow()) {
             mOnAttachStateChangeListener.onViewAttachedToWindow(mLockIcon);
         }
         mLockIcon.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
-        mLockIcon.setStatusBarState(mStatusBarStateController.getState());
+        setStatusBarState(mStatusBarStateController.getState());
     }
 
     public LockIcon getView() {
@@ -228,8 +369,10 @@
      * Called whenever the scrims become opaque, transparent or semi-transparent.
      */
     public void onScrimVisibilityChanged(Integer scrimsVisible) {
-        if (mLockIcon != null) {
-            mLockIcon.onScrimVisibilityChanged(scrimsVisible);
+        if (mWakeAndUnlockRunning
+                && scrimsVisible == ScrimController.TRANSPARENT) {
+            mWakeAndUnlockRunning = false;
+            update();
         }
     }
 
@@ -237,55 +380,56 @@
      * Propagate {@link StatusBar} pulsing state.
      */
     public void setPulsing(boolean pulsing) {
-        if (mLockIcon != null) {
-            mLockIcon.setPulsing(pulsing);
-        }
+        mPulsing = pulsing;
+        update();
     }
 
     /**
-     * Called when the biometric authentication mode changes.
-     *
-     * @param wakeAndUnlock If the type is {@link BiometricUnlockController#isWakeAndUnlock()}
-     * @param isUnlock      If the type is {@link BiometricUnlockController#isBiometricUnlock()} ()
+     * We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
+     * icon on top of the black front scrim.
+     * @param wakeAndUnlock are we wake and unlocking
+     * @param isUnlock are we currently unlocking
      */
     public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
-        if (mLockIcon != null) {
-            mLockIcon.onBiometricAuthModeChanged(wakeAndUnlock, isUnlock);
+        if (wakeAndUnlock) {
+            mWakeAndUnlockRunning = true;
         }
+        if (isUnlock && mKeyguardBypassController.getBypassEnabled() && canBlockUpdates()) {
+            // We don't want the icon to change while we are unlocking
+            mBlockUpdates = true;
+        }
+        update();
     }
 
     /**
      * When we're launching an affordance, like double pressing power to open camera.
      */
     public void onShowingLaunchAffordanceChanged(Boolean showing) {
-        if (mLockIcon != null) {
-            mLockIcon.onShowingLaunchAffordanceChanged(showing);
-        }
+        mShowingLaunchAffordance = showing;
+        update();
     }
 
     /** Sets whether the bouncer is showing. */
     public void setBouncerShowingScrimmed(boolean bouncerShowing) {
-        if (mLockIcon != null) {
-            mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
+        mBouncerShowingScrimmed = bouncerShowing;
+        if (mKeyguardBypassController.getBypassEnabled()) {
+            update();
         }
     }
 
     /**
-     * When {@link KeyguardBouncer} starts to be dismissed and starts to play its animation.
+     * Animate padlock opening when bouncer challenge is solved.
      */
     public void onBouncerPreHideAnimation() {
-        if (mLockIcon != null) {
-            mLockIcon.onBouncerPreHideAnimation();
-        }
+        update();
     }
 
     /**
      * If we're currently presenting an authentication error message.
      */
     public void setTransientBiometricsError(boolean transientBiometricsError) {
-        if (mLockIcon != null) {
-            mLockIcon.setTransientBiometricsError(transientBiometricsError);
-        }
+        mTransientBiometricsError = transientBiometricsError;
+        update();
     }
 
     private boolean handleLongClick(View view) {
@@ -306,4 +450,90 @@
         }
         mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */);
     }
+
+    private void update() {
+        update(false /* force */);
+    }
+
+    private void update(boolean force) {
+        int state = getState();
+        boolean shouldUpdate = mLastState != state || force;
+        if (mBlockUpdates && canBlockUpdates()) {
+            shouldUpdate = false;
+        }
+        if (shouldUpdate && mLockIcon != null) {
+            mLockIcon.update(mLastState, mPulsing, mDozing, mKeyguardJustShown);
+        }
+        mLastState = state;
+        mKeyguardJustShown = false;
+        updateIconVisibility();
+        updateClickability();
+    }
+
+    private int getState() {
+        if ((mKeyguardStateController.canDismissLockScreen() || !mKeyguardShowing
+                || mKeyguardStateController.isKeyguardGoingAway()) && !mSimLocked) {
+            return STATE_LOCK_OPEN;
+        } else if (mTransientBiometricsError) {
+            return STATE_BIOMETRICS_ERROR;
+        } else if (mKeyguardUpdateMonitor.isFaceDetectionRunning() && !mPulsing) {
+            return STATE_SCANNING_FACE;
+        } else {
+            return STATE_LOCKED;
+        }
+    }
+
+    private boolean canBlockUpdates() {
+        return mKeyguardShowing || mKeyguardStateController.isKeyguardFadingAway();
+    }
+
+    private void setDozing(boolean isDozing) {
+        mDozing = isDozing;
+        update();
+    }
+
+    /** Set the StatusBarState. */
+    private void setStatusBarState(int statusBarState) {
+        mStatusBarState = statusBarState;
+        updateIconVisibility();
+    }
+
+    /**
+     * Update the icon visibility
+     * @return true if the visibility changed
+     */
+    private boolean updateIconVisibility() {
+        boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
+        boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
+                || mShowingLaunchAffordance;
+        if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+            if ((mHeadsUpManagerPhone.isHeadsUpGoingAway()
+                    || mHeadsUpManagerPhone.hasPinnedHeadsUp()
+                    || mStatusBarState == StatusBarState.KEYGUARD)
+                    && !mNotificationWakeUpCoordinator.getNotificationsFullyHidden()) {
+                invisible = true;
+            }
+        }
+
+        if (mLockIcon == null) {
+            return false;
+        }
+
+        return mLockIcon.updateIconVisibility(!invisible);
+    }
+
+    private void updateClickability() {
+        if (mAccessibilityController == null) {
+            return;
+        }
+        boolean canLock = mKeyguardStateController.isMethodSecure()
+                && mKeyguardStateController.canDismissLockScreen();
+        boolean clickToUnlock = mAccessibilityController.isAccessibilityEnabled();
+        if (mLockIcon != null) {
+            mLockIcon.setClickable(clickToUnlock);
+            mLockIcon.setLongClickable(canLock && !clickToUnlock);
+            mLockIcon.setFocusable(mAccessibilityController.isAccessibilityEnabled());
+        }
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 7c96386..c2fc18f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -37,10 +37,10 @@
 
 public class WifiSignalController extends
         SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
-    private final boolean mHasMobileData;
+    private final boolean mHasMobileDataFeature;
     private final WifiStatusTracker mWifiTracker;
 
-    public WifiSignalController(Context context, boolean hasMobileData,
+    public WifiSignalController(Context context, boolean hasMobileDataFeature,
             CallbackHandler callbackHandler, NetworkControllerImpl networkController,
             WifiManager wifiManager) {
         super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI,
@@ -52,7 +52,7 @@
         mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
                 connectivityManager, this::handleStatusUpdated);
         mWifiTracker.setListening(true);
-        mHasMobileData = hasMobileData;
+        mHasMobileDataFeature = hasMobileDataFeature;
         if (wifiManager != null) {
             wifiManager.registerTrafficStateCallback(context.getMainExecutor(),
                     new WifiTrafficStateCallback());
@@ -85,9 +85,10 @@
         // only show wifi in the cluster if connected or if wifi-only
         boolean visibleWhenEnabled = mContext.getResources().getBoolean(
                 R.bool.config_showWifiIndicatorWhenEnabled);
-        boolean wifiVisible = mCurrentState.enabled
-                && ((mCurrentState.connected && mCurrentState.inetCondition == 1)
-                    || !mHasMobileData || visibleWhenEnabled);
+        boolean wifiVisible = mCurrentState.enabled && (
+                (mCurrentState.connected && mCurrentState.inetCondition == 1)
+                        || !mHasMobileDataFeature || mWifiTracker.isDefaultNetwork
+                        || visibleWhenEnabled);
         String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null;
         boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
         String contentDescription = getTextIfExists(getContentDescription()).toString();
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index 56aae17..c637123 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -34,7 +34,6 @@
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
-import com.android.systemui.statusbar.phone.LockIcon;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
@@ -148,11 +147,6 @@
         KeyguardMessageArea createKeyguardMessageArea();
 
         /**
-         * Creates the keyguard LockIcon.
-         */
-        LockIcon createLockIcon();
-
-        /**
          * Creates the QSPanel.
          */
         QSPanel createQSPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
index 5411839..bae5bb4 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayImeController.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -97,7 +98,7 @@
         }
         if (mSystemWindows.mDisplayController.getDisplayLayout(displayId).rotation()
                 != pd.mRotation && isImeShowing(displayId)) {
-            pd.startAnimation(true);
+            pd.startAnimation(true, false /* forceRestart */);
         }
     }
 
@@ -200,7 +201,15 @@
                         continue;
                     }
                     if (activeControl.getType() == InsetsState.ITYPE_IME) {
-                        mImeSourceControl = activeControl;
+                        mHandler.post(() -> {
+                            final Point lastSurfacePosition = mImeSourceControl != null
+                                    ? mImeSourceControl.getSurfacePosition() : null;
+                            mImeSourceControl = activeControl;
+                            if (!activeControl.getSurfacePosition().equals(lastSurfacePosition)
+                                    && mAnimation != null) {
+                                startAnimation(mImeShowing, true /* forceRestart */);
+                            }
+                        });
                     }
                 }
             }
@@ -212,7 +221,7 @@
                 return;
             }
             if (DEBUG) Slog.d(TAG, "Got showInsets for ime");
-            startAnimation(true /* show */);
+            startAnimation(true /* show */, false /* forceRestart */);
         }
 
         @Override
@@ -221,7 +230,7 @@
                 return;
             }
             if (DEBUG) Slog.d(TAG, "Got hideInsets for ime");
-            startAnimation(false /* show */);
+            startAnimation(false /* show */, false /* forceRestart */);
         }
 
         /**
@@ -239,7 +248,7 @@
             return imeSource.getFrame().top + (int) surfaceOffset;
         }
 
-        private void startAnimation(final boolean show) {
+        private void startAnimation(final boolean show, final boolean forceRestart) {
             final InsetsSource imeSource = mInsetsState.getSource(InsetsState.ITYPE_IME);
             if (imeSource == null || mImeSourceControl == null) {
                 return;
@@ -250,7 +259,7 @@
                             + (mAnimationDirection == DIRECTION_SHOW ? "SHOW"
                             : (mAnimationDirection == DIRECTION_HIDE ? "HIDE" : "NONE")));
                 }
-                if ((mAnimationDirection == DIRECTION_SHOW && show)
+                if (!forceRestart && (mAnimationDirection == DIRECTION_SHOW && show)
                         || (mAnimationDirection == DIRECTION_HIDE && !show)) {
                     return;
                 }
@@ -270,11 +279,6 @@
                 final float shownY = defaultY;
                 final float startY = show ? hiddenY : shownY;
                 final float endY = show ? shownY : hiddenY;
-                if (mImeShowing && show) {
-                    // IME is already showing, so set seek to end
-                    seekValue = shownY;
-                    seek = true;
-                }
                 mImeShowing = show;
                 mAnimation = ValueAnimator.ofFloat(startY, endY);
                 mAnimation.setDuration(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
index 464a740..072bc44 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMediaPlayerTest.kt
@@ -22,6 +22,8 @@
 import android.testing.TestableLooper
 import android.view.View
 import android.widget.TextView
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.arch.core.executor.TaskExecutor
 import androidx.test.filters.SmallTest
 
 import com.android.systemui.R
@@ -50,25 +52,46 @@
     private lateinit var mediaMetadata: MediaMetadata.Builder
     private lateinit var entry: NotificationEntryBuilder
     @Mock private lateinit var mockView: View
-    private lateinit var textView: TextView
+    private lateinit var songView: TextView
+    private lateinit var artistView: TextView
     @Mock private lateinit var mockIcon: Icon
 
+    private val taskExecutor: TaskExecutor = object : TaskExecutor() {
+        public override fun executeOnDiskIO(runnable: Runnable) {
+            runnable.run()
+        }
+        public override fun postToMainThread(runnable: Runnable) {
+            runnable.run()
+        }
+        public override fun isMainThread(): Boolean {
+            return true
+        }
+    }
+
     @Before
     public fun setup() {
         fakeExecutor = FakeExecutor(FakeSystemClock())
         keyguardMediaPlayer = KeyguardMediaPlayer(context, fakeExecutor)
-        mockView = mock(View::class.java)
-        textView = TextView(context)
         mockIcon = mock(Icon::class.java)
+
+        mockView = mock(View::class.java)
+        songView = TextView(context)
+        artistView = TextView(context)
+        whenever<TextView>(mockView.findViewById(R.id.header_title)).thenReturn(songView)
+        whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(artistView)
+
         mediaMetadata = MediaMetadata.Builder()
         entry = NotificationEntryBuilder()
 
+        ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
+
         keyguardMediaPlayer.bindView(mockView)
     }
 
     @After
     public fun tearDown() {
         keyguardMediaPlayer.unbindView()
+        ArchTaskExecutor.getInstance().setDelegate(null)
     }
 
     @Test
@@ -87,34 +110,36 @@
     @Test
     public fun testUpdateControls() {
         keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
+        FakeExecutor.exhaustExecutors(fakeExecutor)
         verify(mockView).setVisibility(View.VISIBLE)
     }
 
     @Test
     public fun testClearControls() {
         keyguardMediaPlayer.clearControls()
+        FakeExecutor.exhaustExecutors(fakeExecutor)
         verify(mockView).setVisibility(View.GONE)
     }
 
     @Test
     public fun testSongName() {
-        whenever<TextView>(mockView.findViewById(R.id.header_title)).thenReturn(textView)
         val song: String = "Song"
         mediaMetadata.putText(MediaMetadata.METADATA_KEY_TITLE, song)
 
         keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
 
-        assertThat(textView.getText()).isEqualTo(song)
+        assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
+        assertThat(songView.getText()).isEqualTo(song)
     }
 
     @Test
     public fun testArtistName() {
-        whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(textView)
         val artist: String = "Artist"
         mediaMetadata.putText(MediaMetadata.METADATA_KEY_ARTIST, artist)
 
         keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
 
-        assertThat(textView.getText()).isEqualTo(artist)
+        assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
+        assertThat(artistView.getText()).isEqualTo(artist)
     }
 }
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 6e612d7..6f3fbb9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -62,7 +62,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
@@ -90,6 +92,8 @@
 import com.android.systemui.util.FloatingContentCoordinator;
 import com.android.systemui.util.InjectionInflationController;
 
+import com.google.common.collect.ImmutableList;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -136,6 +140,9 @@
     @Mock
     private FloatingContentCoordinator mFloatingContentCoordinator;
 
+    private SysUiState mSysUiState;
+    private boolean mSysUiStateBubblesExpanded;
+
     @Captor
     private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
     @Captor
@@ -229,6 +236,11 @@
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
+        mSysUiState = new SysUiState();
+        mSysUiState.addCallback(sysUiFlags ->
+                mSysUiStateBubblesExpanded =
+                        (sysUiFlags & QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED) != 0);
+
         TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
                 new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
                         mock(PowerManager.class),
@@ -257,7 +269,8 @@
                 mNotifPipeline,
                 mFeatureFlagsOldPipeline,
                 mDumpManager,
-                mFloatingContentCoordinator);
+                mFloatingContentCoordinator,
+                mSysUiState);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -277,6 +290,7 @@
         assertTrue(mBubbleController.hasBubbles());
 
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -284,6 +298,7 @@
         assertFalse(mBubbleController.hasBubbles());
         mBubbleController.updateBubble(mRow.getEntry());
         assertTrue(mBubbleController.hasBubbles());
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -300,6 +315,25 @@
         assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
         verify(mNotificationEntryManager, times(2)).updateNotifications(anyString());
         verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
+
+        assertFalse(mSysUiStateBubblesExpanded);
+    }
+
+    @Test
+    public void testPromoteBubble_autoExpand() {
+        mBubbleController.updateBubble(mRow2.getEntry());
+        mBubbleController.updateBubble(mRow.getEntry());
+        mBubbleController.removeBubble(
+                mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE);
+
+        Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
+        assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
+
+        Bubble b2 = mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey());
+        assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2);
+
+        mBubbleController.promoteBubbleFromOverflow(b);
+        assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b);
     }
 
     @Test
@@ -323,6 +357,8 @@
         verify(mNotificationEntryManager, times(1)).performRemoveNotification(
                 eq(mRow.getEntry().getSbn()), anyInt());
         assertFalse(mBubbleController.hasBubbles());
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -340,6 +376,8 @@
         verify(mNotificationEntryManager, times(3)).updateNotifications(any());
         assertNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
         assertNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -363,6 +401,8 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
         assertTrue(mNotificationShadeWindowController.getBubbleExpanded());
 
+        assertTrue(mSysUiStateBubblesExpanded);
+
         // Make sure the notif is suppressed
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
@@ -372,6 +412,8 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
         assertFalse(mBubbleController.isStackExpanded());
         assertFalse(mNotificationShadeWindowController.getBubbleExpanded());
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -395,6 +437,8 @@
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
+        assertTrue(mSysUiStateBubblesExpanded);
+
         // Last added is the one that is expanded
         assertEquals(mRow2.getEntry(), mBubbleData.getSelectedBubble().getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
@@ -416,6 +460,8 @@
         // Collapse
         mBubbleController.collapseStack();
         assertFalse(mBubbleController.isStackExpanded());
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -437,6 +483,8 @@
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
+        assertTrue(mSysUiStateBubblesExpanded);
+
         // Notif is suppressed after expansion
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
@@ -463,6 +511,8 @@
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
+        assertTrue(mSysUiStateBubblesExpanded);
+
         // Notif is suppressed after expansion
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
@@ -493,6 +543,8 @@
         BubbleStackView stackView = mBubbleController.getStackView();
         mBubbleController.expandStack();
 
+        assertTrue(mSysUiStateBubblesExpanded);
+
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
@@ -522,6 +574,8 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().getKey());
         verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
         assertFalse(mBubbleController.hasBubbles());
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -541,6 +595,8 @@
 
         // # of bubbles should change
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -559,6 +615,8 @@
 
         // # of bubbles should change
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+        assertTrue(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -579,6 +637,8 @@
 
         // # of bubbles should change
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -605,6 +665,8 @@
 
         // # of bubbles should change
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+
+        assertFalse(mSysUiStateBubblesExpanded);
     }
 
     @Test
@@ -619,6 +681,8 @@
                 mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
 
         mBubbleController.expandStackAndSelectBubble(key);
+
+        assertTrue(mSysUiStateBubblesExpanded);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 6244644..a31e3f8d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -58,6 +58,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -132,6 +133,9 @@
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private FloatingContentCoordinator mFloatingContentCoordinator;
+
+    private SysUiState mSysUiState = new SysUiState();
+
     @Captor
     private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
     private TestableBubbleController mBubbleController;
@@ -242,7 +246,8 @@
                 mNotifPipeline,
                 mFeatureFlagsNewPipeline,
                 mDumpManager,
-                mFloatingContentCoordinator);
+                mFloatingContentCoordinator,
+                mSysUiState);
         mBubbleController.addNotifCallback(mNotifCallback);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index d3d90c4..f486102 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.model.SysUiState;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -52,12 +53,13 @@
             NotifPipeline notifPipeline,
             FeatureFlags featureFlags,
             DumpManager dumpManager,
-            FloatingContentCoordinator floatingContentCoordinator) {
+            FloatingContentCoordinator floatingContentCoordinator,
+            SysUiState sysUiState) {
         super(context,
                 notificationShadeWindowController, statusBarStateController, shadeController,
                 data, Runnable::run, configurationController, interruptionStateProvider,
                 zenModeController, lockscreenUserManager, groupManager, entryManager,
-                notifPipeline, featureFlags, dumpManager, floatingContentCoordinator);
+                notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, sysUiState);
         setInflateSynchronously(true);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index d5a654d..eb4d438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -307,6 +307,7 @@
             assertEquals(1, controls.size)
             val controlStatus = controls[0]
             assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId)
+            assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure)
             assertTrue(controlStatus.favorite)
             assertTrue(controlStatus.removed)
 
@@ -337,6 +338,7 @@
             assertEquals(1, controls.size)
             val controlStatus = controls[0]
             assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId)
+            assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure)
             assertTrue(controlStatus.favorite)
             assertFalse(controlStatus.removed)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index f061f34..f4583f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -22,7 +22,6 @@
 import android.view.Choreographer
 import android.view.View
 import android.view.ViewRootImpl
-import androidx.dynamicanimation.animation.SpringAnimation
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
@@ -35,10 +34,14 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito.*
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyFloat
+import org.mockito.Mockito.anyString
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
@@ -56,7 +59,8 @@
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var root: View
     @Mock private lateinit var viewRootImpl: ViewRootImpl
-    @Mock private lateinit var shadeSpring: SpringAnimation
+    @Mock private lateinit var shadeSpring: NotificationShadeDepthController.DepthAnimation
+    @Mock private lateinit var globalActionsSpring: NotificationShadeDepthController.DepthAnimation
     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
 
     private lateinit var statusBarStateListener: StatusBarStateController.StateListener
@@ -76,6 +80,7 @@
                 keyguardStateController, choreographer, wallpaperManager,
                 notificationShadeWindowController, dumpManager)
         notificationShadeDepthController.shadeSpring = shadeSpring
+        notificationShadeDepthController.globalActionsSpring = globalActionsSpring
         notificationShadeDepthController.root = root
 
         val captor = ArgumentCaptor.forClass(StatusBarStateController.StateListener::class.java)
@@ -92,7 +97,7 @@
     fun onPanelExpansionChanged_apliesBlur_ifShade() {
         notificationShadeDepthController.onPanelExpansionChanged(1f /* expansion */,
                 false /* tracking */)
-        verify(shadeSpring).animateToFinalPosition(eq(maxBlur.toFloat()))
+        verify(shadeSpring).animateTo(eq(maxBlur), any())
     }
 
     @Test
@@ -102,13 +107,13 @@
 
         statusBarState = StatusBarState.KEYGUARD
         statusBarStateListener.onStateChanged(statusBarState)
-        verify(shadeSpring).animateToFinalPosition(eq(0f))
+        verify(shadeSpring).animateTo(eq(0), any())
     }
 
     @Test
-    fun updateGlobalDialogVisibility_schedulesUpdate() {
+    fun updateGlobalDialogVisibility_appliesBlur() {
         notificationShadeDepthController.updateGlobalDialogVisibility(0.5f, root)
-        verify(choreographer).postFrameCallback(any())
+        verify(globalActionsSpring).animateTo(eq(maxBlur / 2), safeEq(root))
     }
 
     private fun <T : Any> safeEq(value: T): T {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 261dc82..f4fbd7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -48,7 +48,7 @@
 
     /* ListEntry properties */
     private GroupEntry mParent;
-    private int mSection;
+    private int mSection = -1;
 
     public NotificationEntry build() {
         StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
new file mode 100644
index 0000000..87fc020
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HideNotifsForOtherUsersCoordinatorTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable.PluggableListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class HideNotifsForOtherUsersCoordinatorTest extends SysuiTestCase {
+
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
+    @Mock private NotifPipeline mNotifPipeline;
+    @Mock private PluggableListener<NotifFilter> mInvalidationListener;
+
+    @Captor private ArgumentCaptor<UserChangedListener> mUserChangedListenerCaptor;
+    @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
+
+    private UserChangedListener mCapturedUserChangeListener;
+    private NotifFilter mCapturedNotifFilter;
+
+    private NotificationEntry mEntry = new NotificationEntryBuilder().build();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        HideNotifsForOtherUsersCoordinator coordinator =
+                new HideNotifsForOtherUsersCoordinator(mLockscreenUserManager);
+        coordinator.attach(mNotifPipeline);
+
+        verify(mLockscreenUserManager).addUserChangedListener(mUserChangedListenerCaptor.capture());
+        verify(mNotifPipeline).addPreGroupFilter(mNotifFilterCaptor.capture());
+
+        mCapturedUserChangeListener = mUserChangedListenerCaptor.getValue();
+        mCapturedNotifFilter = mNotifFilterCaptor.getValue();
+
+        mCapturedNotifFilter.setInvalidationListener(mInvalidationListener);
+    }
+
+    @Test
+    public void testFilterOutNotifsFromOtherProfiles() {
+        // GIVEN that all notifs are NOT for the current user
+        when(mLockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(false);
+
+        // THEN they should all be filtered out
+        assertTrue(mCapturedNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void testPreserveNotifsFromThisProfile() {
+        // GIVEN that all notifs ARE for the current user
+        when(mLockscreenUserManager.isCurrentProfile(anyInt())).thenReturn(true);
+
+        // THEN none should be filtered out
+        assertFalse(mCapturedNotifFilter.shouldFilterOut(mEntry, 0));
+    }
+
+    @Test
+    public void testFilterIsInvalidatedWhenProfilesChange() {
+        // WHEN the current user profiles change
+        mCapturedUserChangeListener.onCurrentProfilesChanged(new SparseArray<>());
+
+        // THEN the filter is invalidated
+        verify(mInvalidationListener).onPluggableInvalidated(mCapturedNotifFilter);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index c4f3a16..4f48108 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -102,16 +102,6 @@
     }
 
     @Test
-    public void notificationNotForCurrentProfile() {
-        // GIVEN the notification isn't for the given user
-        setupUnfilteredState(mEntry);
-        when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(false);
-
-        // THEN filter out the entry
-        assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
-    }
-
-    @Test
     public void keyguardNotShowing() {
         // GIVEN the lockscreen isn't showing
         setupUnfilteredState(mEntry);
@@ -229,9 +219,6 @@
      * KeyguardNotificationCoordinator when the keyguard is showing.
      */
     private void setupUnfilteredState(NotificationEntry entry) {
-        // notification is for current profile
-        when(mLockscreenUserManager.isCurrentProfile(NOTIF_USER_ID)).thenReturn(true);
-
         // keyguard is showing
         when(mKeyguardStateController.isShowing()).thenReturn(true);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
index e84f9cf..85acbe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RankingCoordinatorTest.java
@@ -19,9 +19,8 @@
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
 
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,6 +41,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -51,20 +51,23 @@
 
     @Mock private StatusBarStateController mStatusBarStateController;
     @Mock private NotifPipeline mNotifPipeline;
+
+    @Captor private ArgumentCaptor<NotifFilter> mNotifFilterCaptor;
+
     private NotificationEntry mEntry;
-    private RankingCoordinator mRankingCoordinator;
-    private NotifFilter mRankingFilter;
+    private NotifFilter mCapturedSuspendedFilter;
+    private NotifFilter mCapturedDozingFilter;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mRankingCoordinator = new RankingCoordinator(mStatusBarStateController);
+        RankingCoordinator rankingCoordinator = new RankingCoordinator(mStatusBarStateController);
         mEntry = new NotificationEntryBuilder().build();
 
-        ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
-        mRankingCoordinator.attach(mNotifPipeline);
-        verify(mNotifPipeline, times(1)).addPreGroupFilter(filterCaptor.capture());
-        mRankingFilter = filterCaptor.getValue();
+        rankingCoordinator.attach(mNotifPipeline);
+        verify(mNotifPipeline, times(2)).addPreGroupFilter(mNotifFilterCaptor.capture());
+        mCapturedSuspendedFilter = mNotifFilterCaptor.getAllValues().get(0);
+        mCapturedDozingFilter = mNotifFilterCaptor.getAllValues().get(1);
     }
 
     @Test
@@ -73,7 +76,7 @@
         mEntry.setRanking(getRankingForUnfilteredNotif().build());
 
         // THEN don't filter out the notification
-        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mCapturedSuspendedFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -84,7 +87,7 @@
                 .build());
 
         // THEN filter out the notification
-        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mCapturedSuspendedFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -98,13 +101,13 @@
         when(mStatusBarStateController.isDozing()).thenReturn(true);
 
         // THEN filter out the notification
-        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0));
 
         // WHEN it's not dozing (showing the notification list)
         when(mStatusBarStateController.isDozing()).thenReturn(false);
 
         // THEN don't filter out the notification
-        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mCapturedDozingFilter.shouldFilterOut(mEntry, 0));
     }
 
     @Test
@@ -118,13 +121,13 @@
         when(mStatusBarStateController.isDozing()).thenReturn(true);
 
         // THEN don't filter out the notification
-        assertFalse(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertFalse(mCapturedDozingFilter.shouldFilterOut(mEntry, 0));
 
         // WHEN it's not dozing (showing the notification list)
         when(mStatusBarStateController.isDozing()).thenReturn(false);
 
         // THEN filter out the notification
-        assertTrue(mRankingFilter.shouldFilterOut(mEntry, 0));
+        assertTrue(mCapturedDozingFilter.shouldFilterOut(mEntry, 0));
     }
 
     private RankingBuilder getRankingForUnfilteredNotif() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
index 487885a..85b5d70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LockscreenIconControllerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.content.res.Resources;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
@@ -35,6 +36,7 @@
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -71,6 +73,12 @@
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private DockManager mDockManager;
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+    @Mock
+    private Resources mResources;
+    @Mock
+    private HeadsUpManagerPhone mHeadsUpManagerPhone;
 
 
     @Before
@@ -81,7 +89,8 @@
                 mLockscreenGestureLogger, mKeyguardUpdateMonitor, mLockPatternUtils,
                 mShadeController, mAccessibilityController, mKeyguardIndicationController,
                 mStatusBarStateController, mConfigurationController, mNotificationWakeUpCoordinator,
-                mKeyguardBypassController, mDockManager);
+                mKeyguardBypassController, mDockManager, mKeyguardStateController, mResources,
+                mHeadsUpManagerPhone);
 
         mLockIconController.attach(mLockIcon);
     }
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 2fbba68..6af5fe5 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -60,6 +60,7 @@
     hostdex: true, // for hiddenapi check
     visibility: ["//frameworks/base/packages/Tethering:__subpackages__"],
     apex_available: ["com.android.tethering"],
+    permitted_packages: ["android.net"],
 }
 
 stubs_defaults {
@@ -125,17 +126,17 @@
 java_library {
     name: "framework-tethering-stubs-publicapi",
     srcs: [":framework-tethering-stubs-srcs-publicapi"],
-    sdk_version: "current",
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
 }
 
 java_library {
     name: "framework-tethering-stubs-systemapi",
     srcs: [":framework-tethering-stubs-srcs-systemapi"],
-    sdk_version: "system_current",
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
 }
 
 java_library {
     name: "framework-tethering-stubs-module_libs_api",
     srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
-    sdk_version: "module_current",
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
 }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 36113ac..c84892d 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -303,7 +303,8 @@
 
         final UserManager userManager = (UserManager) mContext.getSystemService(
                 Context.USER_SERVICE);
-        mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
+        mTetheringRestriction = new UserRestrictionActionListener(
+                userManager, this, mNotificationUpdater);
         mExecutor = new TetheringThreadExecutor(mHandler);
         mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
 
@@ -369,9 +370,10 @@
 
             mActiveDataSubId = subId;
             updateConfiguration();
+            mNotificationUpdater.onActiveDataSubscriptionIdChanged(subId);
             // To avoid launching unexpected provisioning checks, ignore re-provisioning
             // when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning()
-            // ill be triggered again when CarrierConfig is loaded.
+            // will be triggered again when CarrierConfig is loaded.
             if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
                 mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
             } else {
@@ -431,9 +433,7 @@
         // Called by wifi when the number of soft AP clients changed.
         @Override
         public void onConnectedClientsChanged(final List<WifiClient> clients) {
-            if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, clients)) {
-                reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
-            }
+            updateConnectedClients(clients);
         }
     }
 
@@ -635,7 +635,10 @@
                 Context.ETHERNET_SERVICE);
         synchronized (mPublicSync) {
             if (enable) {
-                if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR;
+                if (mEthernetCallback != null) {
+                    Log.d(TAG, "Ethernet tethering already started");
+                    return TETHER_ERROR_NO_ERROR;
+                }
 
                 mEthernetCallback = new EthernetCallback();
                 mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
@@ -996,11 +999,14 @@
     protected static class UserRestrictionActionListener {
         private final UserManager mUserManager;
         private final Tethering mWrapper;
+        private final TetheringNotificationUpdater mNotificationUpdater;
         public boolean mDisallowTethering;
 
-        public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
+        public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
+                @NonNull TetheringNotificationUpdater updater) {
             mUserManager = um;
             mWrapper = wrapper;
+            mNotificationUpdater = updater;
             mDisallowTethering = false;
         }
 
@@ -1019,13 +1025,21 @@
                 return;
             }
 
-            // TODO: Add user restrictions notification.
-            final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
-
-            if (newlyDisallowed && isTetheringActiveOnDevice) {
-                mWrapper.untetherAll();
-                // TODO(b/148139325): send tetheringSupported on restriction change
+            if (!newlyDisallowed) {
+                // Clear the restricted notification when user is allowed to have tethering
+                // function.
+                mNotificationUpdater.tetheringRestrictionLifted();
+                return;
             }
+
+            // Restricted notification is shown when tethering function is disallowed on
+            // user's device.
+            mNotificationUpdater.notifyTetheringDisabledByRestriction();
+
+            // Untether from all downstreams since tethering is disallowed.
+            mWrapper.untetherAll();
+
+            // TODO(b/148139325): send tetheringSupported on restriction change
         }
     }
 
@@ -1559,6 +1573,7 @@
             mIPv6TetheringCoordinator.removeActiveDownstream(who);
             mOffload.excludeDownstreamInterface(who.interfaceName());
             mForwardedDownstreams.remove(who);
+            updateConnectedClients(null /* wifiClients */);
 
             // If this is a Wi-Fi interface, tell WifiManager of any errors
             // or the inactive serving state.
@@ -2141,6 +2156,12 @@
         return false;
     }
 
+    private void updateConnectedClients(final List<WifiClient> wifiClients) {
+        if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) {
+            reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
+        }
+    }
+
     private IpServer.Callback makeControlCallback() {
         return new IpServer.Callback() {
             @Override
@@ -2155,10 +2176,7 @@
 
             @Override
             public void dhcpLeasesChanged() {
-                if (mConnectedClientsTracker.updateConnectedClients(
-                        mForwardedDownstreams, null /* wifiClients */)) {
-                    reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
-                }
+                updateConnectedClients(null /* wifiClients */);
             }
         };
     }
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
index b97f752..992cdd8 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringNotificationUpdater.java
@@ -29,12 +29,14 @@
 import android.content.res.Resources;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.telephony.SubscriptionManager;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 
 import androidx.annotation.ArrayRes;
 import androidx.annotation.DrawableRes;
+import androidx.annotation.IntDef;
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 
@@ -54,10 +56,15 @@
 public class TetheringNotificationUpdater {
     private static final String TAG = TetheringNotificationUpdater.class.getSimpleName();
     private static final String CHANNEL_ID = "TETHERING_STATUS";
+    private static final String WIFI_DOWNSTREAM = "WIFI";
+    private static final String USB_DOWNSTREAM = "USB";
+    private static final String BLUETOOTH_DOWNSTREAM = "BT";
     private static final boolean NOTIFY_DONE = true;
     private static final boolean NO_NOTIFY = false;
     // Id to update and cancel tethering notification. Must be unique within the tethering app.
-    private static final int NOTIFY_ID = 20191115;
+    private static final int ENABLE_NOTIFICATION_ID = 1000;
+    // Id to update and cancel restricted notification. Must be unique within the tethering app.
+    private static final int RESTRICTED_NOTIFICATION_ID = 1001;
     @VisibleForTesting
     static final int NO_ICON_ID = 0;
     @VisibleForTesting
@@ -65,14 +72,25 @@
     private final Context mContext;
     private final NotificationManager mNotificationManager;
     private final NotificationChannel mChannel;
-    // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
-    // This value has to be made 1 2 and 4, and OR'd with the others.
+
     // WARNING : the constructor is called on a different thread. Thread safety therefore
     // relies on this value being initialized to 0, and not any other value. If you need
     // to change this, you will need to change the thread where the constructor is invoked,
     // or to introduce synchronization.
+    // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
+    // This value has to be made 1 2 and 4, and OR'd with the others.
     private int mDownstreamTypesMask = DOWNSTREAM_NONE;
 
+    // WARNING : this value is not able to being initialized to 0 and must have volatile because
+    // telephony service is not guaranteed that is up before tethering service starts. If telephony
+    // is up later than tethering, TetheringNotificationUpdater will use incorrect and valid
+    // subscription id(0) to query resources. Therefore, initialized subscription id must be
+    // INVALID_SUBSCRIPTION_ID.
+    private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+    @IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID})
+    @interface NotificationId {}
+
     public TetheringNotificationUpdater(@NonNull final Context context) {
         mContext = context;
         mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
@@ -88,19 +106,46 @@
     public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
         if (mDownstreamTypesMask == downstreamTypesMask) return;
         mDownstreamTypesMask = downstreamTypesMask;
-        updateNotification();
+        updateEnableNotification();
     }
 
-    private void updateNotification() {
+    /** Called when active data subscription id changed */
+    public void onActiveDataSubscriptionIdChanged(final int subId) {
+        if (mActiveDataSubId == subId) return;
+        mActiveDataSubId = subId;
+        updateEnableNotification();
+    }
+
+    @VisibleForTesting
+    Resources getResourcesForSubId(@NonNull final Context c, final int subId) {
+        return SubscriptionManager.getResourcesForSubId(c, subId);
+    }
+
+    private void updateEnableNotification() {
         final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE;
 
         if (tetheringInactive || setupNotification() == NO_NOTIFY) {
-            clearNotification();
+            clearNotification(ENABLE_NOTIFICATION_ID);
         }
     }
 
-    private void clearNotification() {
-        mNotificationManager.cancel(null /* tag */, NOTIFY_ID);
+    @VisibleForTesting
+    void tetheringRestrictionLifted() {
+        clearNotification(RESTRICTED_NOTIFICATION_ID);
+    }
+
+    private void clearNotification(@NotificationId final int id) {
+        mNotificationManager.cancel(null /* tag */, id);
+    }
+
+    @VisibleForTesting
+    void notifyTetheringDisabledByRestriction() {
+        final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+        final String title = res.getString(R.string.disable_tether_notification_title);
+        final String message = res.getString(R.string.disable_tether_notification_message);
+
+        showNotification(R.drawable.stat_sys_tether_general, title, message,
+                RESTRICTED_NOTIFICATION_ID);
     }
 
     /**
@@ -110,16 +155,17 @@
      *
      * @return downstream types mask value.
      */
+    @VisibleForTesting
     @IntRange(from = 0, to = 7)
-    private int getDownstreamTypesMask(@NonNull final String types) {
+    int getDownstreamTypesMask(@NonNull final String types) {
         int downstreamTypesMask = DOWNSTREAM_NONE;
         final String[] downstreams = types.split("\\|");
         for (String downstream : downstreams) {
-            if ("USB".equals(downstream.trim())) {
+            if (USB_DOWNSTREAM.equals(downstream.trim())) {
                 downstreamTypesMask |= (1 << TETHERING_USB);
-            } else if ("WIFI".equals(downstream.trim())) {
+            } else if (WIFI_DOWNSTREAM.equals(downstream.trim())) {
                 downstreamTypesMask |= (1 << TETHERING_WIFI);
-            } else if ("BT".equals(downstream.trim())) {
+            } else if (BLUETOOTH_DOWNSTREAM.equals(downstream.trim())) {
                 downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
             }
         }
@@ -134,9 +180,8 @@
      *
      * @return {@link android.util.SparseArray} with downstream types and icon id info.
      */
-    @NonNull
-    private SparseArray<Integer> getIcons(@ArrayRes int id) {
-        final Resources res = mContext.getResources();
+    @VisibleForTesting
+    SparseArray<Integer> getIcons(@ArrayRes int id, @NonNull Resources res) {
         final String[] array = res.getStringArray(id);
         final SparseArray<Integer> icons = new SparseArray<>();
         for (String config : array) {
@@ -161,8 +206,9 @@
     }
 
     private boolean setupNotification() {
-        final Resources res = mContext.getResources();
-        final SparseArray<Integer> downstreamIcons = getIcons(R.array.tethering_notification_icons);
+        final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
+        final SparseArray<Integer> downstreamIcons =
+                getIcons(R.array.tethering_notification_icons, res);
 
         final int iconId = downstreamIcons.get(mDownstreamTypesMask, NO_ICON_ID);
         if (iconId == NO_ICON_ID) return NO_NOTIFY;
@@ -170,12 +216,12 @@
         final String title = res.getString(R.string.tethering_notification_title);
         final String message = res.getString(R.string.tethering_notification_message);
 
-        showNotification(iconId, title, message);
+        showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID);
         return NOTIFY_DONE;
     }
 
     private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
-            @NonNull final String message) {
+            @NonNull final String message, @NotificationId final int id) {
         final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS);
         final PendingIntent pi = PendingIntent.getActivity(
                 mContext.createContextAsUser(UserHandle.CURRENT, 0),
@@ -193,6 +239,6 @@
                         .setContentIntent(pi)
                         .build();
 
-        mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification);
+        mNotificationManager.notify(null /* tag */, id, notification);
     }
 }
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
new file mode 100644
index 0000000..b869491
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringNotificationUpdaterTest.kt
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering
+
+import android.app.Notification
+import android.app.NotificationManager
+import android.content.Context
+import android.content.res.Resources
+import android.net.ConnectivityManager.TETHERING_BLUETOOTH
+import android.net.ConnectivityManager.TETHERING_USB
+import android.net.ConnectivityManager.TETHERING_WIFI
+import android.os.UserHandle
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.internal.util.test.BroadcastInterceptingContext
+import com.android.networkstack.tethering.R
+import com.android.server.connectivity.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.Mock
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+const val TEST_SUBID = 1
+const val WIFI_ICON_ID = 1
+const val USB_ICON_ID = 2
+const val BT_ICON_ID = 3
+const val GENERAL_ICON_ID = 4
+const val WIFI_MASK = 1 shl TETHERING_WIFI
+const val USB_MASK = 1 shl TETHERING_USB
+const val BT_MASK = 1 shl TETHERING_BLUETOOTH
+const val TITTLE = "Tethering active"
+const val MESSAGE = "Tap here to set up."
+const val TEST_TITTLE = "Hotspot active"
+const val TEST_MESSAGE = "Tap to set up hotspot."
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class TetheringNotificationUpdaterTest {
+    // lateinit used here for mocks as they need to be reinitialized between each test and the test
+    // should crash if they are used before being initialized.
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var notificationManager: NotificationManager
+    @Mock private lateinit var defaultResources: Resources
+    @Mock private lateinit var testResources: Resources
+
+    // lateinit for this class under test, as it should be reset to a different instance for every
+    // tests but should always be initialized before use (or the test should crash).
+    private lateinit var notificationUpdater: TetheringNotificationUpdater
+
+    private val ENABLE_ICON_CONFIGS = arrayOf(
+            "USB;android.test:drawable/usb", "BT;android.test:drawable/bluetooth",
+            "WIFI|BT;android.test:drawable/general", "WIFI|USB;android.test:drawable/general",
+            "USB|BT;android.test:drawable/general", "WIFI|USB|BT;android.test:drawable/general")
+
+    private inner class TestContext(c: Context) : BroadcastInterceptingContext(c) {
+        override fun createContextAsUser(user: UserHandle, flags: Int) =
+                if (user == UserHandle.ALL) mockContext else this
+    }
+
+    private inner class WrappedNotificationUpdater(c: Context) : TetheringNotificationUpdater(c) {
+        override fun getResourcesForSubId(context: Context, subId: Int) =
+                if (subId == TEST_SUBID) testResources else defaultResources
+    }
+
+    private fun setupResources() {
+        doReturn(ENABLE_ICON_CONFIGS).`when`(defaultResources)
+                .getStringArray(R.array.tethering_notification_icons)
+        doReturn(arrayOf("WIFI;android.test:drawable/wifi")).`when`(testResources)
+                .getStringArray(R.array.tethering_notification_icons)
+        doReturn(TITTLE).`when`(defaultResources).getString(R.string.tethering_notification_title)
+        doReturn(MESSAGE).`when`(defaultResources)
+                .getString(R.string.tethering_notification_message)
+        doReturn(TEST_TITTLE).`when`(testResources).getString(R.string.tethering_notification_title)
+        doReturn(TEST_MESSAGE).`when`(testResources)
+                .getString(R.string.tethering_notification_message)
+        doReturn(USB_ICON_ID).`when`(defaultResources)
+                .getIdentifier(eq("android.test:drawable/usb"), any(), any())
+        doReturn(BT_ICON_ID).`when`(defaultResources)
+                .getIdentifier(eq("android.test:drawable/bluetooth"), any(), any())
+        doReturn(GENERAL_ICON_ID).`when`(defaultResources)
+                .getIdentifier(eq("android.test:drawable/general"), any(), any())
+        doReturn(WIFI_ICON_ID).`when`(testResources)
+                .getIdentifier(eq("android.test:drawable/wifi"), any(), any())
+    }
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        val context = TestContext(InstrumentationRegistry.getInstrumentation().context)
+        doReturn(notificationManager).`when`(mockContext)
+                .getSystemService(Context.NOTIFICATION_SERVICE)
+        notificationUpdater = WrappedNotificationUpdater(context)
+        setupResources()
+    }
+
+    private fun Notification.title() = this.extras.getString(Notification.EXTRA_TITLE)
+    private fun Notification.text() = this.extras.getString(Notification.EXTRA_TEXT)
+
+    private fun verifyNotification(iconId: Int = 0, title: String = "", text: String = "") {
+        verify(notificationManager, never()).cancel(any(), anyInt())
+
+        val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
+        verify(notificationManager, times(1))
+                .notify(any(), anyInt(), notificationCaptor.capture())
+
+        val notification = notificationCaptor.getValue()
+        assertEquals(iconId, notification.smallIcon.resId)
+        assertEquals(title, notification.title())
+        assertEquals(text, notification.text())
+
+        reset(notificationManager)
+    }
+
+    private fun verifyNoNotification() {
+        verify(notificationManager, times(1)).cancel(any(), anyInt())
+        verify(notificationManager, never()).notify(any(), anyInt(), any())
+
+        reset(notificationManager)
+    }
+
+    @Test
+    fun testNotificationWithDownstreamChanged() {
+        // Wifi downstream. No notification.
+        notificationUpdater.onDownstreamChanged(WIFI_MASK)
+        verifyNoNotification()
+
+        // Same downstream changed. Nothing happened.
+        notificationUpdater.onDownstreamChanged(WIFI_MASK)
+        verifyZeroInteractions(notificationManager)
+
+        // Wifi and usb downstreams. Show enable notification
+        notificationUpdater.onDownstreamChanged(WIFI_MASK or USB_MASK)
+        verifyNotification(GENERAL_ICON_ID, TITTLE, MESSAGE)
+
+        // Usb downstream. Still show enable notification.
+        notificationUpdater.onDownstreamChanged(USB_MASK)
+        verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+        // No downstream. No notification.
+        notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+        verifyNoNotification()
+    }
+
+    @Test
+    fun testNotificationWithActiveDataSubscriptionIdChanged() {
+        // Usb downstream. Showed enable notification with default resource.
+        notificationUpdater.onDownstreamChanged(USB_MASK)
+        verifyNotification(USB_ICON_ID, TITTLE, MESSAGE)
+
+        // Same subId changed. Nothing happened.
+        notificationUpdater.onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+        verifyZeroInteractions(notificationManager)
+
+        // Set test sub id. Clear notification with test resource.
+        notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+        verifyNoNotification()
+
+        // Wifi downstream. Show enable notification with test resource.
+        notificationUpdater.onDownstreamChanged(WIFI_MASK)
+        verifyNotification(WIFI_ICON_ID, TEST_TITTLE, TEST_MESSAGE)
+
+        // No downstream. No notification.
+        notificationUpdater.onDownstreamChanged(DOWNSTREAM_NONE)
+        verifyNoNotification()
+    }
+
+    private fun assertIconNumbers(number: Int, configs: Array<String?>) {
+        doReturn(configs).`when`(defaultResources)
+                .getStringArray(R.array.tethering_notification_icons)
+        assertEquals(number, notificationUpdater.getIcons(
+                R.array.tethering_notification_icons, defaultResources).size())
+    }
+
+    @Test
+    fun testGetIcons() {
+        assertIconNumbers(0, arrayOfNulls<String>(0))
+        assertIconNumbers(0, arrayOf(null, ""))
+        assertIconNumbers(3, arrayOf(
+                // These configurations are invalid with wrong strings or symbols.
+                ";", ",", "|", "|,;", "WIFI", "1;2", " U SB; ", "bt;", "WIFI;USB;BT", "WIFI|USB|BT",
+                "WIFI,BT,USB", " WIFI| |  | USB, test:drawable/test",
+                // This configuration is valid with two downstream types (USB, BT).
+                "USB|,,,,,|BT;drawable/test ",
+                // This configuration is valid with one downstream types (WIFI).
+                "     WIFI     ; android.test:drawable/xxx "))
+    }
+
+    @Test
+    fun testGetDownstreamTypesMask() {
+        assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask(""))
+        assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("1"))
+        assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("WIFI_P2P"))
+        assertEquals(DOWNSTREAM_NONE, notificationUpdater.getDownstreamTypesMask("usb"))
+        assertEquals(WIFI_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI "))
+        assertEquals(USB_MASK, notificationUpdater.getDownstreamTypesMask("USB | B T"))
+        assertEquals(BT_MASK, notificationUpdater.getDownstreamTypesMask(" WIFI: | BT"))
+        assertEquals(WIFI_MASK or USB_MASK,
+                notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||"))
+    }
+
+    @Test
+    fun testSetupRestrictedNotification() {
+        val title = InstrumentationRegistry.getInstrumentation().context.resources
+                .getString(R.string.disable_tether_notification_title)
+        val message = InstrumentationRegistry.getInstrumentation().context.resources
+                .getString(R.string.disable_tether_notification_message)
+        val disallowTitle = "Tether function is disallowed"
+        val disallowMessage = "Please contact your admin"
+        doReturn(title).`when`(defaultResources)
+                .getString(R.string.disable_tether_notification_title)
+        doReturn(message).`when`(defaultResources)
+                .getString(R.string.disable_tether_notification_message)
+        doReturn(disallowTitle).`when`(testResources)
+                .getString(R.string.disable_tether_notification_title)
+        doReturn(disallowMessage).`when`(testResources)
+                .getString(R.string.disable_tether_notification_message)
+
+        // User restrictions on. Show restricted notification.
+        notificationUpdater.notifyTetheringDisabledByRestriction()
+        verifyNotification(R.drawable.stat_sys_tether_general, title, message)
+
+        // User restrictions off. Clear notification.
+        notificationUpdater.tetheringRestrictionLifted()
+        verifyNoNotification()
+
+        // Set test sub id. No notification.
+        notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
+        verifyNoNotification()
+
+        // User restrictions on again. Show restricted notification with test resource.
+        notificationUpdater.notifyTetheringDisabledByRestriction()
+        verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage)
+    }
+}
\ No newline at end of file
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 60d7ad1..5ead110 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -210,7 +210,6 @@
     private PhoneStateListener mPhoneStateListener;
     private InterfaceConfigurationParcel mInterfaceConfiguration;
 
-
     private class TestContext extends BroadcastInterceptingContext {
         TestContext(Context base) {
             super(base);
@@ -1073,13 +1072,15 @@
         when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
 
         final Tethering.UserRestrictionActionListener ural =
-                new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
+                new Tethering.UserRestrictionActionListener(
+                        mUserManager, mockTethering, mNotificationUpdater);
         ural.mDisallowTethering = currentDisallow;
 
         ural.onUserRestrictionsChanged();
 
-        verify(mockTethering, times(expectedInteractionsWithShowNotification))
-                .untetherAll();
+        verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
+                .notifyTetheringDisabledByRestriction();
+        verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
     }
 
     @Test
@@ -1087,7 +1088,7 @@
         final String[] emptyActiveIfacesList = new String[]{};
         final boolean currDisallow = false;
         final boolean nextDisallow = true;
-        final int expectedInteractionsWithShowNotification = 0;
+        final int expectedInteractionsWithShowNotification = 1;
 
         runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
                 expectedInteractionsWithShowNotification);
@@ -1399,6 +1400,7 @@
         mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
         final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
         assertEquals(fakeSubId, newConfig.activeDataSubId);
+        verify(mNotificationUpdater, times(1)).onActiveDataSubscriptionIdChanged(eq(fakeSubId));
     }
 
     @Test
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index 6112da5..fe9f60f 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -37,7 +37,6 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
-import android.util.Size;
 import android.view.Display;
 import android.view.View;
 import android.widget.Toast;
@@ -358,8 +357,8 @@
         // Get the crop
         boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
 
-        Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
-        boolean isPortrait = windowSize.getWidth() < windowSize.getHeight();
+        Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds();
+        boolean isPortrait = windowBounds.width() < windowBounds.height();
 
         Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
                 getDisplay());
diff --git a/services/Android.bp b/services/Android.bp
index 490481c..52c5993 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -142,6 +142,11 @@
             baseline_file: "api/lint-baseline.txt",
         },
     },
+    dist: {
+        targets: ["sdk", "win_sdk"],
+        dir: "apistubs/android/system-server/api",
+        dest: "android.txt",
+    },
 }
 
 java_library {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 60c3d78..1b180e3 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2001,17 +2001,6 @@
                 Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
                 userState.mUserId, currentTargets, str -> str);
         scheduleNotifyClientsOfServicesStateChangeLocked(userState);
-
-        // Disable accessibility shortcut key if there's no shortcut installed.
-        if (currentTargets.isEmpty()) {
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
     }
 
     private boolean canRequestAndRequestsTouchExplorationLocked(
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e49c1ed..c6a54fc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -50,6 +50,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.DeviceConfig;
@@ -63,6 +64,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -151,6 +153,7 @@
     private final LocalLog mWtfHistory = new LocalLog(50);
 
     private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+    private final DisabledInfoCache mDisabledInfoCache = new DisabledInfoCache();
 
     private final LocalService mLocalService = new LocalService();
     private final ActivityManagerInternal mAm;
@@ -302,14 +305,15 @@
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
-        return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
-                mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
+        return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory, mWtfHistory,
+                resolvedUserId, mUi, mAutofillCompatState, disabled, mDisabledInfoCache);
     }
 
     @Override // AbstractMasterSystemService
     protected void onServiceRemoved(@NonNull AutofillManagerServiceImpl service,
             @UserIdInt int userId) {
         service.destroyLocked();
+        mDisabledInfoCache.remove(userId);
         mAutofillCompatState.removeCompatibilityModeRequests(userId);
     }
 
@@ -835,15 +839,10 @@
 
         private void injectDisableAppInfo(@NonNull AutofillOptions options, int userId,
                 String packageName) {
-            synchronized (mLock) {
-                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
-                if (service != null) {
-                    options.appDisabledExpiration = service.getAppDisabledExpirationLocked(
-                            packageName);
-                    options.disabledActivities = service.getAppDisabledActivitiesLocked(
-                            packageName);
-                }
-            }
+            options.appDisabledExpiration =
+                    mDisabledInfoCache.getAppDisabledExpiration(userId, packageName);
+            options.disabledActivities =
+                    mDisabledInfoCache.getAppDisabledActivities(userId, packageName);
         }
     }
 
@@ -867,6 +866,234 @@
     }
 
     /**
+     * Stores autofill disable information, i.e. {@link AutofillDisabledInfo},  keyed by user id.
+     * The information is cleaned up when the service is removed.
+     */
+    static final class DisabledInfoCache {
+
+        private final Object mLock = new Object();
+
+        @GuardedBy("mLock")
+        private final SparseArray<AutofillDisabledInfo> mCache = new SparseArray<>();
+
+        void remove(@UserIdInt int userId) {
+            synchronized (mLock) {
+                mCache.remove(userId);
+            }
+        }
+
+        void addDisabledAppLocked(@UserIdInt int userId, @NonNull String packageName,
+                long expiration) {
+            Preconditions.checkNotNull(packageName);
+            synchronized (mLock) {
+                AutofillDisabledInfo info =
+                        getOrCreateAutofillDisabledInfoByUserIdLocked(userId);
+                info.putDisableAppsLocked(packageName, expiration);
+            }
+        }
+
+        void addDisabledActivityLocked(@UserIdInt int userId, @NonNull ComponentName componentName,
+                long expiration) {
+            Preconditions.checkNotNull(componentName);
+            synchronized (mLock) {
+                AutofillDisabledInfo info =
+                        getOrCreateAutofillDisabledInfoByUserIdLocked(userId);
+                info.putDisableActivityLocked(componentName, expiration);
+            }
+        }
+
+        boolean isAutofillDisabledLocked(@UserIdInt int userId,
+                @NonNull ComponentName componentName) {
+            Preconditions.checkNotNull(componentName);
+            final boolean disabled;
+            synchronized (mLock) {
+                final AutofillDisabledInfo info = mCache.get(userId);
+                disabled = info != null ? info.isAutofillDisabledLocked(componentName) : false;
+            }
+            return disabled;
+        }
+
+        long getAppDisabledExpiration(@UserIdInt int userId, @NonNull String packageName) {
+            Preconditions.checkNotNull(packageName);
+            final Long expiration;
+            synchronized (mLock) {
+                final AutofillDisabledInfo info = mCache.get(userId);
+                expiration = info != null ? info.getAppDisabledExpirationLocked(packageName) : 0;
+            }
+            return expiration;
+        }
+
+        @Nullable
+        ArrayMap<String, Long> getAppDisabledActivities(@UserIdInt int userId,
+                @NonNull String packageName) {
+            Preconditions.checkNotNull(packageName);
+            final ArrayMap<String, Long> disabledList;
+            synchronized (mLock) {
+                final AutofillDisabledInfo info = mCache.get(userId);
+                disabledList =
+                        info != null ? info.getAppDisabledActivitiesLocked(packageName) : null;
+            }
+            return disabledList;
+        }
+
+        void dump(@UserIdInt int userId, String prefix, PrintWriter pw) {
+            synchronized (mLock) {
+                final AutofillDisabledInfo info = mCache.get(userId);
+                if (info != null) {
+                    info.dumpLocked(prefix, pw);
+                }
+            }
+        }
+
+        @NonNull
+        private AutofillDisabledInfo getOrCreateAutofillDisabledInfoByUserIdLocked(
+                @UserIdInt int userId) {
+            AutofillDisabledInfo info = mCache.get(userId);
+            if (info == null) {
+                info = new AutofillDisabledInfo();
+                mCache.put(userId, info);
+            }
+            return info;
+        }
+    }
+
+    /**
+     * The autofill disable information.
+     * <p>
+     * This contains disable information set by the AutofillService, e.g. disabled application
+     * expiration, disable activity expiration.
+     */
+    private static final class AutofillDisabledInfo {
+        /**
+         * Apps disabled by the service; key is package name, value is when they will be enabled
+         * again.
+         */
+        private ArrayMap<String, Long> mDisabledApps;
+        /**
+         * Activities disabled by the service; key is component name, value is when they will be
+         * enabled again.
+         */
+        private ArrayMap<ComponentName, Long> mDisabledActivities;
+
+        void putDisableAppsLocked(@NonNull String packageName, long expiration) {
+            if (mDisabledApps == null) {
+                mDisabledApps = new ArrayMap<>(1);
+            }
+            mDisabledApps.put(packageName, expiration);
+        }
+
+        void putDisableActivityLocked(@NonNull ComponentName componentName, long expiration) {
+            if (mDisabledActivities == null) {
+                mDisabledActivities = new ArrayMap<>(1);
+            }
+            mDisabledActivities.put(componentName, expiration);
+        }
+
+        long getAppDisabledExpirationLocked(@NonNull String packageName) {
+            if (mDisabledApps == null) {
+                return 0;
+            }
+            final Long expiration = mDisabledApps.get(packageName);
+            return expiration != null ? expiration : 0;
+        }
+
+        ArrayMap<String, Long> getAppDisabledActivitiesLocked(@NonNull String packageName) {
+            if (mDisabledActivities != null) {
+                final int size = mDisabledActivities.size();
+                ArrayMap<String, Long> disabledList = null;
+                for (int i = 0; i < size; i++) {
+                    final ComponentName component = mDisabledActivities.keyAt(i);
+                    if (packageName.equals(component.getPackageName())) {
+                        if (disabledList == null) {
+                            disabledList = new ArrayMap<>();
+                        }
+                        final long expiration = mDisabledActivities.valueAt(i);
+                        disabledList.put(component.flattenToShortString(), expiration);
+                    }
+                }
+                return disabledList;
+            }
+            return null;
+        }
+
+        boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
+            // Check activities first.
+            long elapsedTime = 0;
+            if (mDisabledActivities != null) {
+                elapsedTime = SystemClock.elapsedRealtime();
+                final Long expiration = mDisabledActivities.get(componentName);
+                if (expiration != null) {
+                    if (expiration >= elapsedTime) return true;
+                    // Restriction expired - clean it up.
+                    if (sVerbose) {
+                        Slog.v(TAG, "Removing " + componentName.toShortString()
+                                + " from disabled list");
+                    }
+                    mDisabledActivities.remove(componentName);
+                }
+            }
+
+            // Then check apps.
+            final String packageName = componentName.getPackageName();
+            if (mDisabledApps == null) return false;
+
+            final Long expiration = mDisabledApps.get(packageName);
+            if (expiration == null) return false;
+
+            if (elapsedTime == 0) {
+                elapsedTime = SystemClock.elapsedRealtime();
+            }
+
+            if (expiration >= elapsedTime) return true;
+
+            // Restriction expired - clean it up.
+            if (sVerbose)  Slog.v(TAG, "Removing " + packageName + " from disabled list");
+            mDisabledApps.remove(packageName);
+            return false;
+        }
+
+        void dumpLocked(String prefix, PrintWriter pw) {
+            pw.print(prefix); pw.print("Disabled apps: ");
+            if (mDisabledApps == null) {
+                pw.println("N/A");
+            } else {
+                final int size = mDisabledApps.size();
+                pw.println(size);
+                final StringBuilder builder = new StringBuilder();
+                final long now = SystemClock.elapsedRealtime();
+                for (int i = 0; i < size; i++) {
+                    final String packageName = mDisabledApps.keyAt(i);
+                    final long expiration = mDisabledApps.valueAt(i);
+                    builder.append(prefix).append(prefix)
+                            .append(i).append(". ").append(packageName).append(": ");
+                    TimeUtils.formatDuration((expiration - now), builder);
+                    builder.append('\n');
+                }
+                pw.println(builder);
+            }
+
+            pw.print(prefix); pw.print("Disabled activities: ");
+            if (mDisabledActivities == null) {
+                pw.println("N/A");
+            } else {
+                final int size = mDisabledActivities.size();
+                pw.println(size);
+                final StringBuilder builder = new StringBuilder();
+                final long now = SystemClock.elapsedRealtime();
+                for (int i = 0; i < size; i++) {
+                    final ComponentName component = mDisabledActivities.keyAt(i);
+                    final long expiration = mDisabledActivities.valueAt(i);
+                    builder.append(prefix).append(prefix)
+                            .append(i).append(". ").append(component).append(": ");
+                    TimeUtils.formatDuration((expiration - now), builder);
+                    builder.append('\n');
+                }
+                pw.println(builder);
+            }
+        }
+    }
+
+    /**
      * Compatibility mode metadata associated with all services.
      *
      * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 6fbe141..d1805d9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -67,7 +67,6 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -80,6 +79,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
 import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
+import com.android.server.autofill.AutofillManagerService.DisabledInfoCache;
 import com.android.server.autofill.RemoteAugmentedAutofillService.RemoteAugmentedAutofillServiceCallbacks;
 import com.android.server.autofill.ui.AutoFillUI;
 import com.android.server.contentcapture.ContentCaptureManagerInternal;
@@ -90,7 +90,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
-
 /**
  * Bridge between the {@code system_server}'s {@link AutofillManagerService} and the
  * app's {@link IAutoFillService} implementation.
@@ -125,19 +124,6 @@
     private RemoteInlineSuggestionRenderService mRemoteInlineSuggestionRenderService;
 
     /**
-     * Apps disabled by the service; key is package name, value is when they will be enabled again.
-     */
-    @GuardedBy("mLock")
-    private ArrayMap<String, Long> mDisabledApps;
-
-    /**
-     * Activities disabled by the service; key is component name, value is when they will be enabled
-     * again.
-     */
-    @GuardedBy("mLock")
-    private ArrayMap<ComponentName, Long> mDisabledActivities;
-
-    /**
      * Data used for field classification.
      */
     @GuardedBy("mLock")
@@ -186,10 +172,12 @@
 
     private final ContentCaptureManagerInternal mContentCaptureManagerInternal;
 
+    private final DisabledInfoCache mDisabledInfoCache;
+
     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
             AutofillCompatState autofillCompatState,
-            boolean disabled) {
+            boolean disabled, DisabledInfoCache disableCache) {
         super(master, lock, userId);
 
         mUiLatencyHistory = uiLatencyHistory;
@@ -200,7 +188,7 @@
         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
         mContentCaptureManagerInternal = LocalServices.getService(
                 ContentCaptureManagerInternal.class);
-
+        mDisabledInfoCache = disableCache;
         updateLocked(disabled);
     }
 
@@ -1045,45 +1033,7 @@
         pw.println(isInlineSuggestionsEnabled());
         pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
-        pw.print(prefix); pw.print("Disabled apps: ");
-
-        if (mDisabledApps == null) {
-            pw.println("N/A");
-        } else {
-            final int size = mDisabledApps.size();
-            pw.println(size);
-            final StringBuilder builder = new StringBuilder();
-            final long now = SystemClock.elapsedRealtime();
-            for (int i = 0; i < size; i++) {
-                final String packageName = mDisabledApps.keyAt(i);
-                final long expiration = mDisabledApps.valueAt(i);
-                builder.append(prefix).append(prefix)
-                        .append(i).append(". ").append(packageName).append(": ");
-                TimeUtils.formatDuration((expiration - now), builder);
-                builder.append('\n');
-            }
-            pw.println(builder);
-        }
-
-        pw.print(prefix); pw.print("Disabled activities: ");
-
-        if (mDisabledActivities == null) {
-            pw.println("N/A");
-        } else {
-            final int size = mDisabledActivities.size();
-            pw.println(size);
-            final StringBuilder builder = new StringBuilder();
-            final long now = SystemClock.elapsedRealtime();
-            for (int i = 0; i < size; i++) {
-                final ComponentName component = mDisabledActivities.keyAt(i);
-                final long expiration = mDisabledActivities.valueAt(i);
-                builder.append(prefix).append(prefix)
-                        .append(i).append(". ").append(component).append(": ");
-                TimeUtils.formatDuration((expiration - now), builder);
-                builder.append('\n');
-            }
-            pw.println(builder);
-        }
+        mDisabledInfoCache.dump(mUserId, prefix, pw);
 
         final int size = mSessions.size();
         if (size == 0) {
@@ -1480,15 +1430,13 @@
     void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
             boolean compatMode) {
         synchronized (mLock) {
-            if (mDisabledApps == null) {
-                mDisabledApps = new ArrayMap<>(1);
-            }
             long expiration = SystemClock.elapsedRealtime() + duration;
             // Protect it against overflow
             if (expiration < 0) {
                 expiration = Long.MAX_VALUE;
             }
-            mDisabledApps.put(packageName, expiration);
+            mDisabledInfoCache.addDisabledAppLocked(mUserId, packageName, expiration);
+
             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
                     packageName, getServicePackageName(), sessionId, compatMode)
@@ -1502,15 +1450,12 @@
     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
             int sessionId, boolean compatMode) {
         synchronized (mLock) {
-            if (mDisabledActivities == null) {
-                mDisabledActivities = new ArrayMap<>(1);
-            }
             long expiration = SystemClock.elapsedRealtime() + duration;
             // Protect it against overflow
             if (expiration < 0) {
                 expiration = Long.MAX_VALUE;
             }
-            mDisabledActivities.put(componentName, expiration);
+            mDisabledInfoCache.addDisabledActivityLocked(mUserId, componentName, expiration);
             final int intDuration = duration > Integer.MAX_VALUE
                     ? Integer.MAX_VALUE
                     : (int) duration;
@@ -1528,74 +1473,12 @@
         }
     }
 
-    // Called by AutofillManagerService
-    long getAppDisabledExpirationLocked(@NonNull String packageName) {
-        if (mDisabledApps == null) {
-            return 0;
-        }
-        final Long expiration = mDisabledApps.get(packageName);
-        return expiration != null ? expiration : 0;
-    }
-
-    // Called by AutofillManagerService
-    @Nullable
-    ArrayMap<String, Long> getAppDisabledActivitiesLocked(@NonNull String packageName) {
-        if (mDisabledActivities != null) {
-            final int size = mDisabledActivities.size();
-            ArrayMap<String, Long> disabledList = null;
-            for (int i = 0; i < size; i++) {
-                final ComponentName component = mDisabledActivities.keyAt(i);
-                if (packageName.equals(component.getPackageName())) {
-                    if (disabledList == null) {
-                        disabledList = new ArrayMap<>();
-                    }
-                    final long expiration = mDisabledActivities.valueAt(i);
-                    disabledList.put(component.flattenToShortString(), expiration);
-                }
-            }
-            return disabledList;
-        }
-        return null;
-    }
-
     /**
      * Checks if autofill is disabled by service to the given activity.
      */
     @GuardedBy("mLock")
     private boolean isAutofillDisabledLocked(@NonNull ComponentName componentName) {
-        // Check activities first.
-        long elapsedTime = 0;
-        if (mDisabledActivities != null) {
-            elapsedTime = SystemClock.elapsedRealtime();
-            final Long expiration = mDisabledActivities.get(componentName);
-            if (expiration != null) {
-                if (expiration >= elapsedTime) return true;
-                // Restriction expired - clean it up.
-                if (sVerbose) {
-                    Slog.v(TAG, "Removing " + componentName.toShortString()
-                        + " from disabled list");
-                }
-                mDisabledActivities.remove(componentName);
-            }
-        }
-
-        // Then check apps.
-        final String packageName = componentName.getPackageName();
-        if (mDisabledApps == null) return false;
-
-        final Long expiration = mDisabledApps.get(packageName);
-        if (expiration == null) return false;
-
-        if (elapsedTime == 0) {
-            elapsedTime = SystemClock.elapsedRealtime();
-        }
-
-        if (expiration >= elapsedTime) return true;
-
-        // Restriction expired - clean it up.
-        if (sVerbose)  Slog.v(TAG, "Removing " + packageName + " from disabled list");
-        mDisabledApps.remove(packageName);
-        return false;
+        return mDisabledInfoCache.isAutofillDisabledLocked(mUserId, componentName);
     }
 
     // Called by AutofillManager, checks UID.
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
index 5de8171..4ba2c3d 100644
--- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
@@ -199,7 +199,10 @@
             return false;
         }
 
-        if (!mImeInputViewStarted || !autofillId.equalsIgnoreSession(mImeFieldId)) {
+        // TODO(b/151846600): IME doesn't have access to the virtual id of the webview, so we
+        //  only compare the view id for now.
+        if (!mImeInputViewStarted || mImeFieldId == null
+                || autofillId.getViewId() != mImeFieldId.getViewId()) {
             if (sDebug) {
                 Log.d(TAG,
                         "onInlineSuggestionsResponseLocked not sent because input view is not "
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index c39e93a..2306329 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -165,7 +165,8 @@
                 Slog.w(TAG, "InlinePresentation not found in dataset");
                 continue;
             }
-            if (!includeDataset(dataset, fieldIndex, filterText)) {
+            if (!inlinePresentation.isPinned()  // don't filter pinned suggestions
+                    && !includeDataset(dataset, fieldIndex, filterText)) {
                 continue;
             }
             InlineSuggestion inlineSuggestion = createInlineSuggestion(isAugmented, dataset,
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index f1f5005..8dd4fa6 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -1101,6 +1101,9 @@
          * Synchronize on BatteryService.
          */
         public void updateLightsLocked() {
+            if (mBatteryLight == null) {
+                return;
+            }
             final int level = mHealthInfo.batteryLevel;
             final int status = mHealthInfo.batteryStatus;
             if (level < mLowBatteryWarningLevel) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 03ca1c6..1bf559a 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -112,9 +112,13 @@
     private static final int USER_SWITCHED_TIME_MS = 200;
     // Delay for the addProxy function in msec
     private static final int ADD_PROXY_DELAY_MS = 100;
+    // Delay for retrying enable and disable in msec
+    private static final int ENABLE_DISABLE_DELAY_MS = 300;
 
     private static final int MESSAGE_ENABLE = 1;
     private static final int MESSAGE_DISABLE = 2;
+    private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
+    private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
     private static final int MESSAGE_REGISTER_ADAPTER = 20;
     private static final int MESSAGE_UNREGISTER_ADAPTER = 21;
     private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
@@ -136,6 +140,7 @@
     private static final int RESTORE_SETTING_TO_OFF = 0;
 
     private static final int MAX_ERROR_RESTART_RETRIES = 6;
+    private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10;
 
     // Bluetooth persisted setting is off
     private static final int BLUETOOTH_OFF = 0;
@@ -166,6 +171,8 @@
     private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
     private boolean mBinding;
     private boolean mUnbinding;
+    private int mWaitForEnableRetry;
+    private int mWaitForDisableRetry;
 
     private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
 
@@ -1678,8 +1685,18 @@
                     break;
 
                 case MESSAGE_ENABLE:
+                    int quietEnable = msg.arg1;
+                    if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
+                            || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+                        // We are handling enable or disable right now, wait for it.
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
+                                quietEnable, 0), ENABLE_DISABLE_DELAY_MS);
+                        break;
+                    }
+
                     if (DBG) {
-                        Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
+                        Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = "
+                                + mBluetooth);
                     }
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     mEnable = true;
@@ -1702,7 +1719,7 @@
                         mBluetoothLock.readLock().unlock();
                     }
 
-                    mQuietEnable = (msg.arg1 == 1);
+                    mQuietEnable = (quietEnable == 1);
                     if (mBluetooth == null) {
                         handleEnable(mQuietEnable);
                     } else {
@@ -1711,8 +1728,8 @@
                         // the previous Bluetooth process has exited. The
                         // waiting period has three components:
                         // (a) Wait until the local state is STATE_OFF. This
-                        //     is accomplished by
-                        //     "waitForState(Set.of(BluetoothAdapter.STATE_OFF))".
+                        //     is accomplished by sending delay a message
+                        //     MESSAGE_HANDLE_ENABLE_DELAYED
                         // (b) Wait until the STATE_OFF state is updated to
                         //     all components.
                         // (c) Wait until the Bluetooth process exits, and
@@ -1722,34 +1739,109 @@
                         // message. The delay time is backed off if Bluetooth
                         // continuously failed to turn on itself.
                         //
-                        waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-                        Message restartMsg =
-                                mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-                        mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+                        mWaitForEnableRetry = 0;
+                        Message enableDelayedMsg =
+                                mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+                        mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
                     }
                     break;
 
                 case MESSAGE_DISABLE:
+                    if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding
+                            || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
+                        // We are handling enable or disable right now, wait for it.
+                        mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE),
+                                ENABLE_DISABLE_DELAY_MS);
+                        break;
+                    }
+
                     if (DBG) {
-                        Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth);
+                        Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth
+                                + ", mBinding = " + mBinding);
                     }
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+
                     if (mEnable && mBluetooth != null) {
-                        waitForState(Set.of(BluetoothAdapter.STATE_ON));
-                        mEnable = false;
-                        handleDisable();
-                        waitForState(Set.of(BluetoothAdapter.STATE_OFF,
-                                BluetoothAdapter.STATE_TURNING_ON,
-                                BluetoothAdapter.STATE_TURNING_OFF,
-                                BluetoothAdapter.STATE_BLE_TURNING_ON,
-                                BluetoothAdapter.STATE_BLE_ON,
-                                BluetoothAdapter.STATE_BLE_TURNING_OFF));
+                        mWaitForDisableRetry = 0;
+                        Message disableDelayedMsg =
+                                mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+                        mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
                     } else {
                         mEnable = false;
                         handleDisable();
                     }
                     break;
 
+                case MESSAGE_HANDLE_ENABLE_DELAYED: {
+                    // The Bluetooth is turning off, wait for STATE_OFF
+                    if (mState != BluetoothAdapter.STATE_OFF) {
+                        if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+                            mWaitForEnableRetry++;
+                            Message enableDelayedMsg =
+                                    mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
+                            mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+                            break;
+                        } else {
+                            Slog.e(TAG, "Wait for STATE_OFF timeout");
+                        }
+                    }
+                    // Either state is changed to STATE_OFF or reaches the maximum retry, we
+                    // should move forward to the next step.
+                    mWaitForEnableRetry = 0;
+                    Message restartMsg =
+                            mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
+                    mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
+                    Slog.d(TAG, "Handle enable is finished");
+                    break;
+                }
+
+                case MESSAGE_HANDLE_DISABLE_DELAYED: {
+                    boolean disabling = (msg.arg1 == 1);
+                    Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling);
+                    if (!disabling) {
+                        // The Bluetooth is turning on, wait for STATE_ON
+                        if (mState != BluetoothAdapter.STATE_ON) {
+                            if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+                                mWaitForDisableRetry++;
+                                Message disableDelayedMsg = mHandler.obtainMessage(
+                                        MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
+                                mHandler.sendMessageDelayed(disableDelayedMsg,
+                                        ENABLE_DISABLE_DELAY_MS);
+                                break;
+                            } else {
+                                Slog.e(TAG, "Wait for STATE_ON timeout");
+                            }
+                        }
+                        // Either state is changed to STATE_ON or reaches the maximum retry, we
+                        // should move forward to the next step.
+                        mWaitForDisableRetry = 0;
+                        mEnable = false;
+                        handleDisable();
+                        // Wait for state exiting STATE_ON
+                        Message disableDelayedMsg =
+                                mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+                        mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
+                    } else {
+                        // The Bluetooth is turning off, wait for exiting STATE_ON
+                        if (mState == BluetoothAdapter.STATE_ON) {
+                            if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
+                                mWaitForDisableRetry++;
+                                Message disableDelayedMsg = mHandler.obtainMessage(
+                                        MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
+                                mHandler.sendMessageDelayed(disableDelayedMsg,
+                                        ENABLE_DISABLE_DELAY_MS);
+                                break;
+                            } else {
+                                Slog.e(TAG, "Wait for exiting STATE_ON timeout");
+                            }
+                        }
+                        // Either state is exited from STATE_ON or reaches the maximum retry, we
+                        // should move forward to the next step.
+                        Slog.d(TAG, "Handle disable is finished");
+                    }
+                    break;
+                }
+
                 case MESSAGE_RESTORE_USER_SETTING:
                     if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
                         if (DBG) {
@@ -2124,6 +2216,7 @@
         try {
             mBluetoothLock.writeLock().lock();
             if ((mBluetooth == null) && (!mBinding)) {
+                Slog.d(TAG, "binding Bluetooth service");
                 //Start bind timeout and bind
                 Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
                 mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
@@ -2493,6 +2586,12 @@
             writer.println("  " + app.getPackageName());
         }
 
+        writer.println("\nBluetoothManagerService:");
+        writer.println("  mEnable:" + mEnable);
+        writer.println("  mQuietEnable:" + mQuietEnable);
+        writer.println("  mEnableExternal:" + mEnableExternal);
+        writer.println("  mQuietEnableExternal:" + mQuietEnableExternal);
+
         writer.println("");
         writer.flush();
         if (args.length == 0) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ec84ae7..76a8e14 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -40,6 +40,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
 import static android.net.NetworkPolicyManager.RULE_NONE;
 import static android.net.NetworkPolicyManager.uidRulesToString;
@@ -50,6 +51,7 @@
 
 import static java.util.Map.Entry;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
@@ -2702,10 +2704,18 @@
 
             switch (msg.what) {
                 case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
-                    final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
+                    NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
                     if (networkCapabilities.hasConnectivityManagedCapability()) {
                         Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                     }
+                    if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
+                        // Make sure the original object is not mutated. NetworkAgent normally
+                        // makes a copy of the capabilities when sending the message through
+                        // the Messenger, but if this ever changes, not making a defensive copy
+                        // here will give attack vectors to clients using this code path.
+                        networkCapabilities = new NetworkCapabilities(networkCapabilities);
+                        networkCapabilities.restrictCapabilitesForTestNetwork();
+                    }
                     updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
                     break;
                 }
@@ -5778,7 +5788,16 @@
     public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
-        enforceNetworkFactoryPermission();
+        if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
+            enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
+            // Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
+            // the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
+            // sees capabilities that may be malicious, which might prevent mistakes in the future.
+            networkCapabilities = new NetworkCapabilities(networkCapabilities);
+            networkCapabilities.restrictCapabilitesForTestNetwork();
+        } else {
+            enforceNetworkFactoryPermission();
+        }
 
         LinkProperties lp = new LinkProperties(linkProperties);
         lp.ensureDirectlyConnectedRoutes();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1bb3c3a..0ddfa1c 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -886,6 +886,7 @@
 
     @Override
     public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException {
+        NetworkStack.checkNetworkStackPermission(mContext);
         try {
             mNetdService.setIPv6AddrGenMode(iface, mode);
         } catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0bf81e0..4d8c86c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -43,6 +43,7 @@
 import static android.os.storage.OnObbStateChangeListener.MOUNTED;
 import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
 import static android.os.storage.StorageManager.PROP_FUSE;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
 import static android.os.storage.StorageManager.PROP_SETTINGS_FUSE;
 
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -155,6 +156,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.pm.Installer;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.storage.AppFuseBridge;
 import com.android.server.storage.StorageSessionController;
 import com.android.server.storage.StorageSessionController.ExternalStorageServiceException;
@@ -902,6 +904,7 @@
                     refreshIsolatedStorageSettings();
                 }
             });
+        updateLegacyStorageOpSticky();
         // For now, simply clone property when it changes
         DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
                 mContext.getMainExecutor(), (properties) -> {
@@ -1778,6 +1781,13 @@
         }
     }
 
+    private void updateLegacyStorageOpSticky() {
+        final boolean propertyValue = DeviceConfig.getBoolean(
+                DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+                "legacy_storage_op_sticky", true);
+        SystemProperties.set(PROP_LEGACY_OP_STICKY, propertyValue ? "true" : "false");
+    }
+
     private void start() {
         connectStoraged();
         connectVold();
@@ -3268,6 +3278,25 @@
         }
     }
 
+    @Override
+    public void fixupAppDir(String path) {
+        final Matcher matcher = KNOWN_APP_DIR_PATHS.matcher(path);
+        if (matcher.matches()) {
+            AndroidPackage pkg = mPmInternal.getPackage(matcher.group(3));
+            if (pkg != null) {
+                try {
+                    mVold.fixupAppDir(path + "/", pkg.getUid());
+                } catch (RemoteException | ServiceSpecificException e) {
+                    Log.e(TAG, "Failed to fixup app dir for " + pkg.getPackageName(), e);
+                }
+            } else {
+                Log.e(TAG, "Can't find package belonging to " + path);
+            }
+        } else {
+            Log.e(TAG, "Path " + path + " is not a valid application-specific directory");
+        }
+    }
+
     /** Not thread safe */
     class AppFuseMountScope extends AppFuseBridge.MountScope {
         private boolean mMounted = false;
@@ -4430,9 +4459,8 @@
                             String.format("/storage/emulated/%d/Android/data/%s/",
                                     userId, pkg);
 
-                    int appUid =
-                            UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
                     // Create package obb and data dir if it doesn't exist.
+                    int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
                     File file = new File(packageObbDir);
                     if (!file.exists()) {
                         vold.setupAppDir(packageObbDir, appUid);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4cfcd2b..38405e1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -185,8 +185,6 @@
 import android.app.ProcessMemoryState;
 import android.app.ProfilerInfo;
 import android.app.WaitResult;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
 import android.app.backup.IBackupManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
@@ -6513,13 +6511,6 @@
     }
 
     @Override
-    public List<RunningTaskInfo> getFilteredTasks(int maxNum, @ActivityType int ignoreActivityType,
-            @WindowingMode int ignoreWindowingMode) {
-        return mActivityTaskManager.getFilteredTasks(
-                maxNum, ignoreActivityType, ignoreWindowingMode);
-    }
-
-    @Override
     public void cancelTaskWindowTransition(int taskId) {
         mActivityTaskManager.cancelTaskWindowTransition(taskId);
     }
@@ -8780,6 +8771,27 @@
     }
 
     @Override
+    public boolean isUidActiveOrForeground(int uid, String callingPackage) {
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "isUidActiveOrForeground");
+        }
+        synchronized (this) {
+            final boolean isActive = isUidActiveLocked(uid);
+            if (isActive) {
+                return true;
+            }
+        }
+        final boolean isForeground = mAtmInternal.isUidForeground(uid);
+        if (isForeground) {
+            Slog.wtf(TAG, "isUidActiveOrForeground: isUidActive false but "
+                    + " isUidForeground true, uid:" + uid
+                    + " callingPackage:" + callingPackage);
+        }
+        return isForeground;
+    }
+
+    @Override
     public void setPersistentVrThread(int tid) {
         mActivityTaskManager.setPersistentVrThread(tid);
     }
diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
index 03f4a54..ba89fce 100644
--- a/services/core/java/com/android/server/am/BugReportHandlerUtil.java
+++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java
@@ -16,20 +16,15 @@
 
 package com.android.server.am;
 
-import static android.app.AppOpsManager.OP_NONE;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
-import android.app.Activity;
 import android.app.BroadcastOptions;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Binder;
-import android.os.BugreportManager;
-import android.os.BugreportParams;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -115,17 +110,9 @@
         options.setBackgroundActivityStartsAllowed(true);
         final long identity = Binder.clearCallingIdentity();
         try {
-            // Handler app's BroadcastReceiver should call setResultCode(Activity.RESULT_OK) to
-            // let ResultBroadcastReceiver know the handler app is available.
-            context.sendOrderedBroadcastAsUser(intent,
-                    UserHandle.of(handlerUser),
+            context.sendBroadcastAsUser(intent, UserHandle.of(handlerUser),
                     android.Manifest.permission.DUMP,
-                    OP_NONE, options.toBundle(),
-                    new ResultBroadcastReceiver(),
-                    /* scheduler= */ null,
-                    Activity.RESULT_CANCELED,
-                    /* initialData= */ null,
-                    /* initialExtras= */ null);
+                    options.toBundle());
         } catch (RuntimeException e) {
             Slog.e(TAG, "Error while trying to launch bugreport handler app.", e);
             return false;
@@ -189,19 +176,4 @@
             Binder.restoreCallingIdentity(identity);
         }
     }
-
-    private static class ResultBroadcastReceiver extends BroadcastReceiver {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (getResultCode() == Activity.RESULT_OK) {
-                return;
-            }
-
-            Slog.w(TAG, "Request bug report because handler app seems to be not available.");
-            BugreportManager bugreportManager = context.getSystemService(BugreportManager.class);
-            bugreportManager.requestBugreport(
-                    new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE),
-                    /* shareTitle= */null, /* shareDescription= */ null);
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 4d08bd2..bee0e05 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -98,6 +98,7 @@
 import android.system.Os;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.LongSparseArray;
 import android.util.Pair;
@@ -138,6 +139,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Activity manager code dealing with processes.
@@ -2155,15 +2157,6 @@
                 result.put(packageName, Pair.create(volumeUuid, inode));
             }
         }
-        if (mAppDataIsolationWhitelistedApps != null) {
-            for (String packageName : mAppDataIsolationWhitelistedApps) {
-                String volumeUuid = pmInt.getPackage(packageName).getVolumeUuid();
-                long inode = pmInt.getCeDataInode(packageName, userId);
-                if (inode != 0) {
-                    result.put(packageName, Pair.create(volumeUuid, inode));
-                }
-            }
-        }
 
         return result;
     }
@@ -2184,34 +2177,42 @@
                 app.setHasForegroundActivities(true);
             }
 
+            final Map<String, Pair<String, Long>> pkgDataInfoMap;
+            final Map<String, Pair<String, Long>> whitelistedAppDataInfoMap;
+            boolean bindMountAppStorageDirs = false;
+            boolean bindMountAppsData = shouldIsolateAppData(app);
+
+            // Get all packages belongs to the same shared uid. sharedPackages is empty array
+            // if it doesn't have shared uid.
+            final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
+            final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
+                    app.info.packageName, app.userId);
+            final String[] targetPackagesList = sharedPackages.length == 0
+                    ? new String[]{app.info.packageName} : sharedPackages;
+            pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, targetPackagesList, uid);
+
+            // Remove all packages in pkgDataInfoMap from mAppDataIsolationWhitelistedApps, so
+            // it won't be mounted twice.
+            final Set<String> whitelistedApps = new ArraySet<>(mAppDataIsolationWhitelistedApps);
+            for (String pkg : targetPackagesList) {
+                whitelistedApps.remove(pkg);
+            }
+            whitelistedAppDataInfoMap = getPackageAppDataInfoMap(pmInt,
+                    whitelistedApps.toArray(new String[0]), uid);
+
+            int userId = UserHandle.getUserId(uid);
             StorageManagerInternal storageManagerInternal = LocalServices.getService(
                     StorageManagerInternal.class);
-            final Map<String, Pair<String, Long>> pkgDataInfoMap;
-            boolean bindMountAppStorageDirs = false;
-
-            if (shouldIsolateAppData(app)) {
-                // Get all packages belongs to the same shared uid. sharedPackages is empty array
-                // if it doesn't have shared uid.
-                final PackageManagerInternal pmInt = mService.getPackageManagerInternalLocked();
-                final String[] sharedPackages = pmInt.getSharedUserPackagesForPackage(
-                        app.info.packageName, app.userId);
-                pkgDataInfoMap = getPackageAppDataInfoMap(pmInt, sharedPackages.length == 0
-                        ? new String[]{app.info.packageName} : sharedPackages, uid);
-
-                int userId = UserHandle.getUserId(uid);
-                if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
-                        !storageManagerInternal.isExternalStorageService(uid)) {
-                    bindMountAppStorageDirs = true;
-                    if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
-                            app.processName)) {
-                        // Cannot prepare Android/app and Android/obb directory,
-                        // so we won't mount it in zygote.
-                        app.bindMountPending = true;
-                        bindMountAppStorageDirs = false;
-                    }
+            if (mVoldAppDataIsolationEnabled && UserHandle.isApp(app.uid) &&
+                    !storageManagerInternal.isExternalStorageService(uid)) {
+                bindMountAppStorageDirs = true;
+                if (!storageManagerInternal.prepareStorageDirs(userId, pkgDataInfoMap.keySet(),
+                        app.processName)) {
+                    // Cannot prepare Android/app and Android/obb directory,
+                    // so we won't mount it in zygote.
+                    app.bindMountPending = true;
+                    bindMountAppStorageDirs = false;
                 }
-            } else {
-                pkgDataInfoMap = null;
             }
 
             final Process.ProcessStartResult startResult;
@@ -2229,7 +2230,8 @@
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, app.info.packageName,
                         /*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
-                        app.mDisabledCompatChanges, pkgDataInfoMap, bindMountAppStorageDirs,
+                        app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
+                        bindMountAppsData, bindMountAppStorageDirs,
                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             } else {
                 startResult = Process.start(entryPoint,
@@ -2237,7 +2239,7 @@
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
                         isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
-                        bindMountAppStorageDirs,
+                        whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
                         new String[]{PROC_START_SEQ_IDENT + app.startSeq});
             }
             checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index ada3e42..94675ab 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -776,6 +776,8 @@
 
         mDeviceBroker = new AudioDeviceBroker(mContext, this);
 
+        mRecordMonitor = new RecordingActivityMonitor(mContext);
+
         // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
         // array initialized by updateStreamVolumeAlias()
         updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
@@ -797,8 +799,6 @@
 
         mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
 
-        mRecordMonitor = new RecordingActivityMonitor(mContext);
-
         readAndSetLowRamDevice();
 
         mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
@@ -1981,8 +1981,7 @@
         }
 
         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-                mFixedVolumeDevices.contains(device)) {
+        if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
             flags |= AudioManager.FLAG_FIXED_VOLUME;
 
             // Always toggle between max safe volume and 0 for fixed volume devices where safe
@@ -2059,7 +2058,7 @@
                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
                 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
                 mVolumeController.postDisplaySafeVolumeWarning(flags);
-            } else if (!mFullVolumeDevices.contains(device)
+            } else if (!isFullVolumeDevice(device)
                     && (streamState.adjustIndex(direction * step, device, caller)
                             || streamState.mIsMuted)) {
                 // Post message to set system volume (it in turn will post a
@@ -2121,7 +2120,7 @@
                     if (mHdmiCecSink
                             && streamTypeAlias == AudioSystem.STREAM_MUSIC
                             // vol change on a full volume device
-                            && mFullVolumeDevices.contains(device)) {
+                            && isFullVolumeDevice(device)) {
                         int keyCode = KeyEvent.KEYCODE_UNKNOWN;
                         switch (direction) {
                             case AudioManager.ADJUST_RAISE:
@@ -2325,6 +2324,13 @@
 
         // For legacy reason, propagate to all streams associated to this volume group
         for (final int groupedStream : vgs.getLegacyStreamTypes()) {
+            try {
+                ensureValidStreamType(groupedStream);
+            } catch (IllegalArgumentException e) {
+                Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream
+                        + "), do not change associated stream volume");
+                continue;
+            }
             setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage,
                             Binder.getCallingUid());
         }
@@ -2590,8 +2596,7 @@
             }
 
             flags &= ~AudioManager.FLAG_FIXED_VOLUME;
-            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
-                    mFixedVolumeDevices.contains(device)) {
+            if (streamTypeAlias == AudioSystem.STREAM_MUSIC && isFixedVolumeDevice(device)) {
                 flags |= AudioManager.FLAG_FIXED_VOLUME;
 
                 // volume is either 0 or max allowed for fixed volume devices
@@ -2780,7 +2785,7 @@
 
         if (streamType == AudioSystem.STREAM_MUSIC) {
             flags = updateFlagsForTvPlatform(flags);
-            if (mFullVolumeDevices.contains(device)) {
+            if (isFullVolumeDevice(device)) {
                 flags &= ~AudioManager.FLAG_SHOW_UI;
             }
         }
@@ -2826,7 +2831,7 @@
                                     int device,
                                     boolean force,
                                     String caller) {
-        if (mFullVolumeDevices.contains(device)) {
+        if (isFullVolumeDevice(device)) {
             return;
         }
         VolumeStreamState streamState = mStreamStates[streamType];
@@ -3036,7 +3041,7 @@
                 index = 0;
             }
             if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
-                    mFixedVolumeDevices.contains(device)) {
+                    isFixedVolumeDevice(device)) {
                 index = mStreamStates[streamType].getMaxIndex();
             }
             return (index + 5) / 10;
@@ -4883,10 +4888,6 @@
 
         public void applyAllVolumes() {
             synchronized (VolumeGroupState.class) {
-                if (mLegacyStreamType != AudioSystem.STREAM_DEFAULT) {
-                    // No-op to avoid regression with stream based volume management
-                    return;
-                }
                 // apply device specific volumes first
                 int index;
                 for (int i = 0; i < mIndexMap.size(); i++) {
@@ -5166,7 +5167,7 @@
             } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                     && isAvrcpAbsVolSupported) {
                 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
-            } else if (mFullVolumeDevices.contains(device)) {
+            } else if (isFullVolumeDevice(device)) {
                 index = (mIndexMax + 5)/10;
             } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                 index = (mIndexMax + 5)/10;
@@ -5189,7 +5190,7 @@
                         } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                                 && isAvrcpAbsVolSupported) {
                             index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
-                        } else if (mFullVolumeDevices.contains(device)) {
+                        } else if (isFullVolumeDevice(device)) {
                             index = (mIndexMax + 5)/10;
                         } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                             index = (mIndexMax + 5)/10;
@@ -5390,8 +5391,8 @@
                     for (int i = 0; i < mIndexMap.size(); i++) {
                         int device = mIndexMap.keyAt(i);
                         int index = mIndexMap.valueAt(i);
-                        if (mFullVolumeDevices.contains(device)
-                                || (mFixedVolumeDevices.contains(device) && index != 0)) {
+                        if (isFullVolumeDevice(device)
+                                || (isFixedVolumeDevice(device) && index != 0)) {
                             mIndexMap.put(device, mIndexMax);
                         }
                         applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
@@ -8236,4 +8237,23 @@
             new HashMap<IBinder, AudioPolicyProxy>();
     @GuardedBy("mAudioPolicies")
     private int mAudioPolicyCounter = 0;
+
+    //======================
+    // Helper functions for full and fixed volume device
+    //======================
+    private boolean isFixedVolumeDevice(int deviceType) {
+        if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+                && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+            return false;
+        }
+        return mFixedVolumeDevices.contains(deviceType);
+    }
+
+    private boolean isFullVolumeDevice(int deviceType) {
+        if (deviceType == AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
+                && mRecordMonitor.isLegacyRemoteSubmixActive()) {
+            return false;
+        }
+        return mFullVolumeDevices.contains(deviceType);
+    }
 }
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index 5c50962..65f2218 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioRecordingConfiguration;
@@ -35,6 +36,8 @@
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Class to receive and dispatch updates from AudioSystem about recording configurations.
@@ -49,6 +52,16 @@
     // playback configurations that do not contain uid/package name information.
     private boolean mHasPublicClients = false;
 
+
+    // When legacy remote submix device is active, remote submix device should not be fixed and
+    // full volume device. When legacy remote submix device is active, there will be a recording
+    // activity using device with type as {@link AudioSystem.DEVICE_OUT_REMOTE_SUBMIX} and address
+    // as {@link AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS}. Cache riid of legacy remote submix
+    // since remote submix state is not cached in mRecordStates.
+    private AtomicInteger mLegacyRemoteSubmixRiid =
+            new AtomicInteger(AudioManager.RECORD_RIID_INVALID);
+    private AtomicBoolean mLegacyRemoteSubmixActive = new AtomicBoolean(false);
+
     static final class RecordingState {
         private final int mRiid;
         private final RecorderDeathHandler mDeathHandler;
@@ -137,6 +150,16 @@
         final AudioRecordingConfiguration config = createRecordingConfiguration(
                 uid, session, source, recordingInfo,
                 portId, silenced, activeSource, clientEffects, effects);
+        if (source == MediaRecorder.AudioSource.REMOTE_SUBMIX) {
+            final AudioDeviceInfo device = config.getAudioDevice();
+            if (AudioSystem.LEGACY_REMOTE_SUBMIX_ADDRESS.equals(device.getAddress())) {
+                mLegacyRemoteSubmixRiid.set(riid);
+                if (event == AudioManager.RECORD_CONFIG_EVENT_START
+                        || event == AudioManager.RECORD_CONFIG_EVENT_UPDATE) {
+                    mLegacyRemoteSubmixActive.set(true);
+                }
+            }
+        }
         if (MediaRecorder.isSystemOnlyAudioSource(source)) {
             // still want to log event, it just won't appear in recording configurations;
             sEventLogger.log(new RecordingEvent(event, riid, config).printLog(TAG));
@@ -170,6 +193,9 @@
      * Receive an event from the client about a tracked recorder
      */
     public void recorderEvent(int riid, int event) {
+        if (mLegacyRemoteSubmixRiid.get() == riid) {
+            mLegacyRemoteSubmixActive.set(event == AudioManager.RECORDER_STATE_STARTED);
+        }
         int configEvent = event == AudioManager.RECORDER_STATE_STARTED
                 ? AudioManager.RECORD_CONFIG_EVENT_START :
                 event == AudioManager.RECORDER_STATE_STOPPED
@@ -323,6 +349,13 @@
     }
 
     /**
+     * Return true if legacy remote submix device is active. Otherwise, return false.
+     */
+    boolean isLegacyRemoteSubmixActive() {
+        return mLegacyRemoteSubmixActive.get();
+    }
+
+    /**
      * Create a recording configuration from the provided parameters
      * @param uid
      * @param session
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index d45ffd9..ff8e3a9 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -202,8 +202,7 @@
 
             // Only allow internal clients to call canAuthenticate with a different userId.
             final int callingUserId = UserHandle.getCallingUserId();
-            Slog.d(TAG, "canAuthenticate, userId: " + userId + ", callingUserId: " + callingUserId
-                    + ", authenticators: " + authenticators);
+
             if (userId != callingUserId) {
                 checkInternalPermission();
             } else {
@@ -212,8 +211,14 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                return mBiometricService.canAuthenticate(
+                final int result = mBiometricService.canAuthenticate(
                         opPackageName, userId, callingUserId, authenticators);
+                Slog.d(TAG, "canAuthenticate"
+                        + ", userId: " + userId
+                        + ", callingUserId: " + callingUserId
+                        + ", authenticators: " + authenticators
+                        + ", result: " + result);
+                return result;
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 766e5c4..5d334c2 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -66,6 +66,8 @@
 
     public abstract boolean wasUserDetected();
 
+    public abstract boolean isStrongBiometric();
+
     public AuthenticationClient(Context context, Constants constants,
             BiometricServiceBase.DaemonWrapper daemon, long halDeviceId, IBinder token,
             BiometricServiceBase.ServiceListener listener, int targetUserId, int groupId, long opId,
@@ -167,9 +169,15 @@
                 }
                 if (isBiometricPrompt() && listener != null) {
                     // BiometricService will add the token to keystore
-                    listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken);
+                    listener.onAuthenticationSucceededInternal(mRequireConfirmation, byteToken,
+                            isStrongBiometric());
                 } else if (!isBiometricPrompt() && listener != null) {
-                    KeyStore.getInstance().addAuthToken(byteToken);
+                    if (isStrongBiometric()) {
+                        KeyStore.getInstance().addAuthToken(byteToken);
+                    } else {
+                        Slog.d(getLogTag(), "Skipping addAuthToken");
+                    }
+
                     try {
                         // Explicitly have if/else here to make it super obvious in case the code is
                         // touched in the future.
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index e7c09ba..233416d 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -266,7 +266,8 @@
                     SomeArgs args = (SomeArgs) msg.obj;
                     handleAuthenticationSucceeded(
                             (boolean) args.arg1 /* requireConfirmation */,
-                            (byte[]) args.arg2 /* token */);
+                            (byte[]) args.arg2 /* token */,
+                            (boolean) args.arg3 /* isStrongBiometric */);
                     args.recycle();
                     break;
                 }
@@ -568,10 +569,12 @@
     final IBiometricServiceReceiverInternal mInternalReceiver =
             new IBiometricServiceReceiverInternal.Stub() {
         @Override
-        public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+        public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+                boolean isStrongBiometric) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = requireConfirmation;
             args.arg2 = token;
+            args.arg3 = isStrongBiometric;
             mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget();
         }
 
@@ -761,8 +764,13 @@
                         + " config_biometric_sensors?");
             }
 
+            // Note that we allow BIOMETRIC_CONVENIENCE to register because BiometricService
+            // also does / will do other things such as keep track of lock screen timeout, etc.
+            // Just because a biometric is registered does not mean it can participate in
+            // the android.hardware.biometrics APIs.
             if (strength != Authenticators.BIOMETRIC_STRONG
-                    && strength != Authenticators.BIOMETRIC_WEAK) {
+                    && strength != Authenticators.BIOMETRIC_WEAK
+                    && strength != Authenticators.BIOMETRIC_CONVENIENCE) {
                 throw new IllegalStateException("Unsupported strength");
             }
 
@@ -1189,8 +1197,10 @@
                         BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL);
             }
         } else {
+            // This should not be possible via the public API surface and is here mainly for
+            // "correctness". An exception should have been thrown before getting here.
             Slog.e(TAG, "No authenticators requested");
-            return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+            return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT);
         }
     }
 
@@ -1286,7 +1296,8 @@
         return modality;
     }
 
-    private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+    private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token,
+            boolean isStrongBiometric) {
         try {
             // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
             // after user dismissed/canceled dialog).
@@ -1295,9 +1306,16 @@
                 return;
             }
 
-            // Store the auth token and submit it to keystore after the dialog is confirmed /
-            // animating away.
-            mCurrentAuthSession.mTokenEscrow = token;
+            if (isStrongBiometric) {
+                // Store the auth token and submit it to keystore after the dialog is confirmed /
+                // animating away.
+                mCurrentAuthSession.mTokenEscrow = token;
+            } else {
+                if (token != null) {
+                    Slog.w(TAG, "Dropping authToken for non-strong biometric");
+                }
+            }
+
             if (!requireConfirmation) {
                 mCurrentAuthSession.mState = STATE_AUTHENTICATED_PENDING_SYSUI;
             } else {
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ebd407d..45b9383 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -413,8 +413,8 @@
             throw new UnsupportedOperationException("Stub!");
         }
 
-        default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
-                throws RemoteException {
+        default void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+                boolean isStrongBiometric) throws RemoteException {
             throw new UnsupportedOperationException("Stub!");
         }
 
@@ -451,10 +451,11 @@
         }
 
         @Override
-        public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token)
-                throws RemoteException {
+        public void onAuthenticationSucceededInternal(boolean requireConfirmation, byte[] token,
+                boolean isStrongBiometric) throws RemoteException {
             if (getWrapperReceiver() != null) {
-                getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token);
+                getWrapperReceiver().onAuthenticationSucceeded(requireConfirmation, token,
+                        isStrongBiometric);
             }
         }
 
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 fd54129..3ecf87c 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -236,6 +236,11 @@
         }
 
         @Override
+        public boolean isStrongBiometric() {
+            return FaceService.this.isStrongBiometric();
+        }
+
+        @Override
         public boolean onAuthenticated(BiometricAuthenticator.Identifier identifier,
                 boolean authenticated, ArrayList<Byte> token) {
             final boolean result = super.onAuthenticated(identifier, authenticated, token);
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index acb1a2f..8520f5a 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -161,6 +161,11 @@
         }
 
         @Override
+        public boolean isStrongBiometric() {
+            return FingerprintService.this.isStrongBiometric();
+        }
+
+        @Override
         public int handleFailedAttempt() {
             final int currentUser = ActivityManager.getCurrentUser();
             mFailedAttempts.put(currentUser, mFailedAttempts.get(currentUser, 0) + 1);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 05a757b..8eb7710 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -646,7 +646,9 @@
                                     + "id=" + physicalDisplayId
                                     + ", state=" + Display.stateToString(state) + ")");
                         }
-                        mBacklight.setVrMode(isVrEnabled);
+                        if (mBacklight != null) {
+                            mBacklight.setVrMode(isVrEnabled);
+                        }
                     }
 
                     private void setDisplayState(int state) {
@@ -708,7 +710,9 @@
                                         BrightnessSynchronizer.brightnessFloatToInt(getContext(),
                                                 brightness));
                             }
-                            mBacklight.setBrightness(brightness);
+                            if (mBacklight != null) {
+                                mBacklight.setBrightness(brightness);
+                            }
                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
                                     "ScreenBrightness",
                                     BrightnessSynchronizer.brightnessFloatToInt(
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 87fe785..ad08663 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -50,6 +50,9 @@
  */
 public class IncidentCompanionService extends SystemService {
     static final String TAG = "IncidentCompanionService";
+    // TODO(b/152289743): Expose below intent.
+    private static final String INTENT_CHECK_USER_CONSENT =
+            "com.android.internal.intent.action.CHECK_USER_CONSENT";
 
     /**
      * Dump argument for proxying restricted image dumps to the services
@@ -89,6 +92,12 @@
 
             final long ident = Binder.clearCallingIdentity();
             try {
+                Intent intent = new Intent(INTENT_CHECK_USER_CONSENT);
+                intent.setPackage(callingPackage);
+                intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+                getContext().sendBroadcast(intent, android.Manifest.permission.DUMP);
+
                 mPendingReports.authorizeReport(callingUid, callingPackage,
                         receiverClass, reportId, flags, listener);
             } finally {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 0b22586..e6129b9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -76,7 +76,6 @@
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.InputMonitor;
-import android.view.InputWindowHandle;
 import android.view.KeyEvent;
 import android.view.PointerIcon;
 import android.view.Surface;
@@ -221,8 +220,7 @@
             int policyFlags);
     private static native VerifiedInputEvent nativeVerifyInputEvent(long ptr, InputEvent event);
     private static native void nativeToggleCapsLock(long ptr, int deviceId);
-    private static native void nativeSetInputWindows(long ptr, InputWindowHandle[] windowHandles,
-            int displayId);
+    private static native void nativeDisplayRemoved(long ptr, int displayId);
     private static native void nativeSetInputDispatchMode(long ptr, boolean enabled, boolean frozen);
     private static native void nativeSetSystemUiVisibility(long ptr, int visibility);
     private static native void nativeSetFocusedApplication(long ptr,
@@ -1536,7 +1534,7 @@
 
     /** Clean up input window handles of the given display. */
     public void onDisplayRemoved(int displayId) {
-        nativeSetInputWindows(mPtr, null /* windowHandles */, displayId);
+        nativeDisplayRemoved(mPtr, displayId);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index 521913a..706c741 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -16,6 +16,7 @@
 
 package com.android.server.lights;
 
+import android.annotation.Nullable;
 import android.hardware.light.V2_0.Type;
 
 public abstract class LightsManager {
@@ -30,7 +31,8 @@
     public static final int LIGHT_ID_COUNT = Type.COUNT;
 
     /**
-     * Returns the logical light with the given type.
+     * Returns the logical light with the given type, if it exists, or null.
      */
+    @Nullable
     public abstract LogicalLight getLight(int id);
 }
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index a42dec8..3c6e8d2 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -52,8 +52,8 @@
     static final String TAG = "LightsService";
     static final boolean DEBUG = false;
 
-    private LightImpl[] mLights = null;
-    private SparseArray<LightImpl> mLightsById = null;
+    private final LightImpl[] mLightsByType = new LightImpl[LightsManager.LIGHT_ID_COUNT];
+    private final SparseArray<LightImpl> mLightsById = new SparseArray<>();
 
     private ILights mVintfLights = null;
 
@@ -96,8 +96,8 @@
             synchronized (LightsService.this) {
                 final List<Light> lights = new ArrayList<Light>();
                 for (int i = 0; i < mLightsById.size(); i++) {
-                    HwLight hwLight = mLightsById.valueAt(i).getHwLight();
-                    if (!isSystemLight(hwLight)) {
+                    if (!mLightsById.valueAt(i).isSystemLight()) {
+                        HwLight hwLight = mLightsById.valueAt(i).mHwLight;
                         lights.add(new Light(hwLight.id, hwLight.ordinal, hwLight.type));
                     }
                 }
@@ -138,7 +138,7 @@
 
             synchronized (LightsService.this) {
                 final LightImpl light = mLightsById.get(lightId);
-                if (light == null || isSystemLight(light.getHwLight())) {
+                if (light == null || light.isSystemLight()) {
                     throw new IllegalArgumentException("Invalid light: " + lightId);
                 }
                 return new LightState(light.getColor());
@@ -184,9 +184,8 @@
         private void checkRequestIsValid(int[] lightIds) {
             for (int i = 0; i < lightIds.length; i++) {
                 final LightImpl light = mLightsById.get(lightIds[i]);
-                final HwLight hwLight = light.getHwLight();
-                Preconditions.checkState(light != null && !isSystemLight(hwLight),
-                        "invalid lightId " + hwLight.id);
+                Preconditions.checkState(light != null && !light.isSystemLight(),
+                        "Invalid lightId " + lightIds[i]);
             }
         }
 
@@ -205,9 +204,8 @@
             }
             for (int i = 0; i < mLightsById.size(); i++) {
                 LightImpl light = mLightsById.valueAt(i);
-                HwLight hwLight = light.getHwLight();
-                if (!isSystemLight(hwLight)) {
-                    LightState state = states.get(hwLight.id);
+                if (!light.isSystemLight()) {
+                    LightState state = states.get(light.mHwLight.id);
                     if (state != null) {
                         light.setColor(state.getColor());
                     } else {
@@ -385,26 +383,22 @@
                 int brightnessMode) {
             Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
                     + Integer.toHexString(color) + ")");
-            if (mVintfLights != null) {
-                HwLightState lightState = new HwLightState();
-                lightState.color = color;
-                lightState.flashMode = (byte) mode;
-                lightState.flashOnMs = onMS;
-                lightState.flashOffMs = offMS;
-                lightState.brightnessMode = (byte) brightnessMode;
-                try {
+            try {
+                if (mVintfLights != null) {
+                    HwLightState lightState = new HwLightState();
+                    lightState.color = color;
+                    lightState.flashMode = (byte) mode;
+                    lightState.flashOnMs = onMS;
+                    lightState.flashOffMs = offMS;
+                    lightState.brightnessMode = (byte) brightnessMode;
                     mVintfLights.setLightState(mHwLight.id, lightState);
-                } catch (RemoteException | UnsupportedOperationException ex) {
-                    Slog.e(TAG, "Failed issuing setLightState", ex);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
-                }
-            } else {
-                try {
+                } else {
                     setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
                 }
+            } catch (RemoteException | UnsupportedOperationException ex) {
+                Slog.e(TAG, "Failed issuing setLightState", ex);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_POWER);
             }
         }
 
@@ -412,8 +406,14 @@
             return mVrModeEnabled && mUseLowPersistenceForVR;
         }
 
-        private HwLight getHwLight() {
-            return mHwLight;
+        /**
+         * Returns whether a light is system-use-only or should be accessible to
+         * applications using the {@link android.hardware.lights.LightsManager} API.
+         */
+        private boolean isSystemLight() {
+            // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system lights.
+            // Newly-added lights are made available via the public LightsManager API.
+            return (0 <= mHwLight.type && mHwLight.type < LightsManager.LIGHT_ID_COUNT);
         }
 
         private int getColor() {
@@ -451,39 +451,40 @@
     }
 
     private void populateAvailableLights(Context context) {
-        mLights = new LightImpl[LightsManager.LIGHT_ID_COUNT];
-        mLightsById = new SparseArray<>();
-
         if (mVintfLights != null) {
-            try {
-                for (HwLight availableLight : mVintfLights.getLights()) {
-                    LightImpl light = new LightImpl(context, availableLight);
-                    int type = (int) availableLight.type;
-                    if (0 <= type && type < mLights.length && mLights[type] == null) {
-                        mLights[type] = light;
-                    }
-                    mLightsById.put(availableLight.id, light);
-                }
-            } catch (RemoteException ex) {
-                Slog.e(TAG, "Unable to get lights for initialization", ex);
-            }
+            populateAvailableLightsFromAidl(context);
+        } else {
+            populateAvailableLightsFromHidl(context);
         }
 
-        // In the case where only the old HAL is available, all lights will be initialized here
-        for (int i = 0; i < mLights.length; i++) {
-            if (mLights[i] == null) {
-                // The ordinal can be anything if there is only 1 light of each type. Set it to 1.
-                HwLight light = new HwLight();
-                light.id = (byte) i;
-                light.ordinal = 1;
-                light.type = (byte) i;
-
-                mLights[i] = new LightImpl(context, light);
-                mLightsById.put(i, mLights[i]);
+        for (int i = mLightsById.size() - 1; i >= 0; i--) {
+            final int type = mLightsById.keyAt(i);
+            if (0 <= type && type < mLightsByType.length) {
+                mLightsByType[type] = mLightsById.valueAt(i);
             }
         }
     }
 
+    private void populateAvailableLightsFromAidl(Context context) {
+        try {
+            for (HwLight hwLight : mVintfLights.getLights()) {
+                mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
+            }
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Unable to get lights from HAL", ex);
+        }
+    }
+
+    private void populateAvailableLightsFromHidl(Context context) {
+        for (int i = 0; i < mLightsByType.length; i++) {
+            HwLight hwLight = new HwLight();
+            hwLight.id = (byte) i;
+            hwLight.ordinal = 1;
+            hwLight.type = (byte) i;
+            mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
+        }
+    }
+
     @Override
     public void onStart() {
         publishLocalService(LightsManager.class, mService);
@@ -505,25 +506,14 @@
     private final LightsManager mService = new LightsManager() {
         @Override
         public LogicalLight getLight(int lightType) {
-            if (mLights != null && 0 <= lightType && lightType < mLights.length) {
-                return mLights[lightType];
+            if (mLightsByType != null && 0 <= lightType && lightType < mLightsByType.length) {
+                return mLightsByType[lightType];
             } else {
                 return null;
             }
         }
     };
 
-    /**
-     * Returns whether a light is system-use-only or should be accessible to
-     * applications using the {@link android.hardware.lights.LightsManager} API.
-     */
-    private static boolean isSystemLight(HwLight light) {
-        // LIGHT_ID_COUNT comes from the 2.0 HIDL HAL and only contains system
-        // lights. Newly added lights will be made available via the
-        // LightsManager API.
-        return 0 <= light.type && light.type < LightsManager.LIGHT_ID_COUNT;
-    }
-
     static native void setLight_native(int light, int color, int mode,
             int onMS, int offMS, int brightnessMode);
 }
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 58e332a..c1fbcfb 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -653,9 +653,6 @@
         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
 
-        mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
-                GnssLocationProvider.this::onNetworkAvailable, mLooper);
-
         // App ops service to keep track of who is accessing the GPS
         mAppOps = mContext.getSystemService(AppOpsManager.class);
 
@@ -677,6 +674,9 @@
         mNIHandler = new GpsNetInitiatedHandler(context,
                 mNetInitiatedListener,
                 mSuplEsEnabled);
+        mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
+                GnssLocationProvider.this::onNetworkAvailable, mLooper, mNIHandler);
+
         sendMessage(INITIALIZE_HANDLER, 0, null);
 
         mGnssStatusListenerHelper = new GnssStatusListenerHelper(mContext, mHandler) {
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 93227bd..5d6474b 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -29,12 +29,22 @@
 import android.provider.Telephony.Carriers;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.PreciseCallState;
+import android.telephony.PhoneStateListener;
 import android.util.Log;
 
+import com.android.internal.location.GpsNetInitiatedHandler;
+
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
+import java.util.Map;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Iterator;
 
 /**
  * Handles network connection requests and network state change updates for AGPS data download.
@@ -86,6 +96,9 @@
     private HashMap<Network, NetworkAttributes> mAvailableNetworkAttributes =
             new HashMap<>(HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS);
 
+    // Phone State Listeners to track all the active sub IDs
+    private HashMap<Integer, SubIdPhoneStateListener> mPhoneStateListeners;
+
     private final ConnectivityManager mConnMgr;
 
     private final Handler mHandler;
@@ -94,6 +107,9 @@
     private int mAGpsDataConnectionState;
     private InetAddress mAGpsDataConnectionIpAddr;
     private int mAGpsType;
+    private int mActiveSubId = -1;
+    private final GpsNetInitiatedHandler mNiHandler;
+
 
     private final Context mContext;
 
@@ -166,18 +182,109 @@
 
     GnssNetworkConnectivityHandler(Context context,
             GnssNetworkListener gnssNetworkListener,
-            Looper looper) {
+            Looper looper,
+            GpsNetInitiatedHandler niHandler) {
         mContext = context;
         mGnssNetworkListener = gnssNetworkListener;
 
+    SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
+        if (subManager != null) {
+            subManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
+        }
+
         PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
 
         mHandler = new Handler(looper);
+        mNiHandler = niHandler;
         mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         mSuplConnectivityCallback = createSuplConnectivityCallback();
     }
 
+    /**
+     * SubId Phone State Listener is used cache the last active Sub ID when a call is made,
+     * which will be used during an emergency call to set the Network Specifier to the particular
+     * sub when an emergency supl connection is requested
+     */
+    private final class SubIdPhoneStateListener extends PhoneStateListener {
+        private Integer mSubId;
+        SubIdPhoneStateListener(Integer subId) {
+            mSubId = subId;
+        }
+        @Override
+        public void onPreciseCallStateChanged(PreciseCallState state) {
+            if (state.PRECISE_CALL_STATE_ACTIVE == state.getForegroundCallState()) {
+                mActiveSubId = mSubId;
+                if (DEBUG) Log.d(TAG, "mActiveSubId: " + mActiveSubId);
+            }
+        }
+    };
+
+    /**
+     * Subscription Changed Listener is used to get all active subscriptions and create a
+     * Phone State Listener for each Sub ID that we find in the active subscription list
+     */
+    private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
+            = new SubscriptionManager.OnSubscriptionsChangedListener() {
+        @Override
+        public void onSubscriptionsChanged() {
+            if (mPhoneStateListeners == null) {
+                // Capacity=2 Load-Factor=1.0, as typically no more than 2 SIMs
+                mPhoneStateListeners = new HashMap<Integer, SubIdPhoneStateListener>(2,1);
+            }
+            SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class);
+            TelephonyManager telManager = mContext.getSystemService(TelephonyManager.class);
+            if (subManager != null && telManager != null) {
+                List<SubscriptionInfo> subscriptionInfoList =
+                        subManager.getActiveSubscriptionInfoList();
+                HashSet<Integer> activeSubIds = new HashSet<Integer>();
+                if (subscriptionInfoList != null) {
+                    if (DEBUG) Log.d(TAG, "Active Sub List size: " + subscriptionInfoList.size());
+                    // populate phone state listeners with all new active subs
+                    for (SubscriptionInfo subInfo : subscriptionInfoList) {
+                        activeSubIds.add(subInfo.getSubscriptionId());
+                        if (!mPhoneStateListeners.containsKey(subInfo.getSubscriptionId())) {
+                            TelephonyManager subIdTelManager =
+                                    telManager.createForSubscriptionId(subInfo.getSubscriptionId());
+                            if (subIdTelManager != null) {
+                                if (DEBUG) Log.d(TAG, "Listener sub" + subInfo.getSubscriptionId());
+                                SubIdPhoneStateListener subIdPhoneStateListener =
+                                        new SubIdPhoneStateListener(subInfo.getSubscriptionId());
+                                mPhoneStateListeners.put(subInfo.getSubscriptionId(),
+                                        subIdPhoneStateListener);
+                                subIdTelManager.listen(subIdPhoneStateListener,
+                                        PhoneStateListener.LISTEN_PRECISE_CALL_STATE);
+                            }
+                        }
+                    }
+                }
+                // clean up phone state listeners than no longer have active subs
+                Iterator<Map.Entry<Integer, SubIdPhoneStateListener> > iterator =
+                        mPhoneStateListeners.entrySet().iterator();
+                while (iterator.hasNext()) {
+                    Map.Entry<Integer, SubIdPhoneStateListener> element = iterator.next();
+                    if (!activeSubIds.contains(element.getKey())) {
+                        TelephonyManager subIdTelManager =
+                                telManager.createForSubscriptionId(element.getKey());
+                        if (subIdTelManager != null) {
+                            if (DEBUG) Log.d(TAG, "unregister listener sub " + element.getKey());
+                            subIdTelManager.listen(element.getValue(),
+                                                   PhoneStateListener.LISTEN_NONE);
+                            // removes the element from mPhoneStateListeners
+                            iterator.remove();
+                        } else {
+                            Log.e(TAG, "Telephony Manager for Sub " + element.getKey() + " null");
+                        }
+                    }
+                }
+                // clean up cached active phone call sub if it is no longer an active sub
+                if (!activeSubIds.contains(mActiveSubId)) {
+                    mActiveSubId = -1;
+                }
+            }
+        }
+    };
+
     void registerNetworkCallbacks() {
         // register for connectivity change events.
         NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
@@ -467,6 +574,12 @@
         NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
         networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType));
         networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        // During an emergency call, and when we have cached the Active Sub Id, we set the
+        // Network Specifier so that the network request goes to the correct Sub Id
+        if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
+            if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId));
+            networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId));
+        }
         NetworkRequest networkRequest = networkRequestBuilder.build();
         mConnMgr.requestNetwork(
                 networkRequest,
@@ -598,6 +711,15 @@
         }
         TelephonyManager phone = (TelephonyManager)
                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
+        // During an emergency call with an active sub id, get the Telephony Manager specific
+        // to the active sub to get the correct value from getServiceState and getNetworkType
+        if (mNiHandler.getInEmergency() && mActiveSubId >= 0) {
+            TelephonyManager subIdTelManager =
+                    phone.createForSubscriptionId(mActiveSubId);
+            if (subIdTelManager != null) {
+                phone = subIdTelManager;
+            }
+        }
         ServiceState serviceState = phone.getServiceState();
         String projection = null;
         String selection = null;
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
index 054f5de..f2eb176 100644
--- a/services/core/java/com/android/server/notification/BubbleExtractor.java
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -157,8 +157,8 @@
         }
 
         /**
-         * @return whether the user has enabled the provided notification to bubble, does not
-         * account for policy.
+         * @return whether the user has enabled the provided notification to bubble, and if the
+         * developer has provided valid information for the notification to bubble.
          */
         @VisibleForTesting
         boolean canBubble(NotificationRecord r, String pkg, int userId) {
@@ -184,8 +184,17 @@
             }
 
             String shortcutId = metadata.getShortcutId();
-            boolean shortcutValid = shortcutId != null
-                    && mShortcutHelper.getValidShortcutInfo(shortcutId, pkg, r.getUser()) != null;
+            String notificationShortcutId = r.getShortcutInfo() != null
+                    ? r.getShortcutInfo().getId()
+                    : null;
+            boolean shortcutValid = false;
+            if (notificationShortcutId != null && shortcutId != null) {
+                // NoMan already checks validity of shortcut, just check if they match.
+                shortcutValid = shortcutId.equals(notificationShortcutId);
+            } else if (shortcutId != null) {
+                shortcutValid =
+                        mShortcutHelper.getValidShortcutInfo(shortcutId, pkg, r.getUser()) != null;
+            }
             if (metadata.getIntent() == null && !shortcutValid) {
                 // Should have a shortcut if intent is null
                 logBubbleError(r.getKey(),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 60c3875..31dc094 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -139,6 +139,7 @@
 import android.app.usage.UsageStatsManagerInternal;
 import android.companion.ICompanionDeviceManager;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -387,10 +388,9 @@
      * still post toasts created with
      * {@link android.widget.Toast#makeText(Context, CharSequence, int)} and its variants while
      * in the background.
-     *
-     * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood
      */
     @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
     private static final long CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK = 128611929L;
 
     private IActivityManager mAm;
@@ -1579,7 +1579,9 @@
                 }
             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                 // turn off LED when user passes through lock screen
-                mNotificationLight.turnOff();
+                if (mNotificationLight != null) {
+                    mNotificationLight.turnOff();
+                }
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 mUserProfiles.updateCache(context);
@@ -2751,24 +2753,18 @@
         @Override
         public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration,
                 int displayId, @Nullable ITransientNotificationCallback callback) {
-            enqueueToast(pkg, token, text, null, duration, displayId, callback, false);
+            enqueueToast(pkg, token, text, null, duration, displayId, callback);
         }
 
         @Override
         public void enqueueToast(String pkg, IBinder token, ITransientNotification callback,
                 int duration, int displayId) {
-            enqueueToast(pkg, token, null, callback, duration, displayId, null, true);
-        }
-
-        @Override
-        public void enqueueTextOrCustomToast(String pkg, IBinder token,
-                ITransientNotification callback, int duration, int displayId, boolean isCustom) {
-            enqueueToast(pkg, token, null, callback, duration, displayId, null, isCustom);
+            enqueueToast(pkg, token, null, callback, duration, displayId, null);
         }
 
         private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text,
                 @Nullable ITransientNotification callback, int duration, int displayId,
-                @Nullable ITransientNotificationCallback textCallback, boolean isCustom) {
+                @Nullable ITransientNotificationCallback textCallback) {
             if (DBG) {
                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token
                         + " duration=" + duration + " displayId=" + displayId);
@@ -2807,11 +2803,15 @@
             }
 
             boolean isAppRenderedToast = (callback != null);
-            if (isAppRenderedToast && isCustom && !isSystemToast
-                    && !isPackageInForegroundForToast(pkg, callingUid)) {
+            if (isAppRenderedToast && !isSystemToast && !isPackageInForegroundForToast(pkg,
+                    callingUid)) {
                 boolean block;
                 long id = Binder.clearCallingIdentity();
                 try {
+                    // CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so block will be
+                    // false for apps with targetSdk < R. For apps with targetSdk R+, text toasts
+                    // are not app-rendered, so isAppRenderedToast == true means it's a custom
+                    // toast.
                     block = mPlatformCompat.isChangeEnabledByPackageName(
                             CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK, pkg,
                             callingUser.getIdentifier());
@@ -2824,11 +2824,6 @@
                     Binder.restoreCallingIdentity(id);
                 }
                 if (block) {
-                    // TODO(b/144152069): Remove informative toast
-                    mUiHandler.post(() -> Toast.makeText(getContext(),
-                            "Background custom toast blocked for package " + pkg + ".\n"
-                                    + "See g.co/dev/toast.",
-                            Toast.LENGTH_SHORT).show());
                     Slog.w(TAG, "Blocking custom toast from package " + pkg
                             + " due to package not in the foreground");
                     return;
@@ -4200,7 +4195,7 @@
         @Override
         public int getInterruptionFilterFromListener(INotificationListener token)
                 throws RemoteException {
-            synchronized (mNotificationLight) {
+            synchronized (mNotificationLock) {
                 return mInterruptionFilter;
             }
         }
@@ -6780,7 +6775,7 @@
         if (canShowLightsLocked(record, aboveThreshold)) {
             mLights.add(key);
             updateLightsLocked();
-            if (mUseAttentionLight) {
+            if (mUseAttentionLight && mAttentionLight != null) {
                 mAttentionLight.pulse();
             }
             blink = true;
@@ -7981,6 +7976,10 @@
     @GuardedBy("mNotificationLock")
     void updateLightsLocked()
     {
+        if (mNotificationLight == null) {
+            return;
+        }
+
         // handle notification lights
         NotificationRecord ledNotification = null;
         while (ledNotification == null && !mLights.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index c37ea8b..c97f33b 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -16,22 +16,22 @@
 
 package com.android.server.pm;
 
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.apex.ApexInfo;
 import android.apex.ApexInfoList;
 import android.apex.ApexSessionInfo;
 import android.apex.ApexSessionParams;
 import android.apex.IApexService;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -44,8 +44,9 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.pm.parsing.PackageParser2;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.utils.TimingsTraceAndSlog;
 
@@ -61,7 +62,9 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
 /**
@@ -72,7 +75,7 @@
 
     private static final String TAG = "ApexManager";
 
-    static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
+    public static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
     static final int MATCH_FACTORY_PACKAGE = 1 << 1;
 
     private static final Singleton<ApexManager> sApexManagerSingleton =
@@ -139,7 +142,14 @@
      */
     public abstract List<ActiveApexInfo> getActiveApexInfos();
 
-    abstract void systemReady(Context context);
+    /**
+     * Called by package manager service to scan apex package files when device boots up.
+     *
+     * @param packageParser The package parser which supports caches.
+     * @param executorService An executor to support parallel package parsing.
+     */
+    abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+            @NonNull ExecutorService executorService);
 
     /**
      * Retrieves information about an APEX package.
@@ -154,7 +164,7 @@
      *         is not found.
      */
     @Nullable
-    abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
+    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
 
     /**
      * Retrieves information about all active APEX packages.
@@ -189,6 +199,27 @@
     abstract boolean isApexPackage(String packageName);
 
     /**
+     * Whether the APEX package is pre-installed or not.
+     *
+     * @param packageInfo the package to check
+     * @return {@code true} if this package is pre-installed, {@code false} otherwise.
+     */
+    public static boolean isFactory(@NonNull PackageInfo packageInfo) {
+        return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    /**
+     * Returns the active apex package's name that contains the (apk) package.
+     *
+     * @param containedPackage The (apk) package that might be in a apex
+     * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside
+     *         any apex.
+     */
+    @Nullable
+    public abstract String getActiveApexPackageNameContainingPackage(
+            @NonNull AndroidPackage containedPackage);
+
+    /**
      * Retrieves information about an apexd staged session i.e. the internal state used by apexd to
      * track the different states of a session.
      *
@@ -342,7 +373,7 @@
          * difference between {@code packageName} and {@code apexModuleName}.
          */
         @GuardedBy("mLock")
-        private Map<String, List<String>> mApksInApex = new ArrayMap<>();
+        private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>();
 
         @GuardedBy("mLock")
         private List<PackageInfo> mAllPackagesCache;
@@ -357,7 +388,7 @@
          * the apk container to {@code apexModuleName} of the apex-payload inside.
          */
         @GuardedBy("mLock")
-        private Map<String, String> mPackageNameToApexModuleName;
+        private ArrayMap<String, String> mPackageNameToApexModuleName;
 
         ApexManagerImpl(IApexService apexService) {
             mApexService = apexService;
@@ -373,16 +404,6 @@
             return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
         }
 
-        /**
-         * Whether the APEX package is pre-installed or not.
-         *
-         * @param packageInfo the package to check
-         * @return {@code true} if this package is pre-installed, {@code false} otherwise.
-         */
-        private static boolean isFactory(PackageInfo packageInfo) {
-            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
-        }
-
         @Override
         public List<ActiveApexInfo> getActiveApexInfos() {
             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
@@ -411,104 +432,94 @@
         }
 
         @Override
-        void systemReady(Context context) {
-            context.registerReceiver(new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    // Post populateAllPackagesCacheIfNeeded to a background thread, since it's
-                    // expensive to run it in broadcast handler thread.
-                    BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded());
-                    context.unregisterReceiver(this);
+        void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+                @NonNull ExecutorService executorService) {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced");
+            try {
+                synchronized (mLock) {
+                    scanApexPackagesInternalLocked(packageParser, executorService);
                 }
-            }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
-        }
-
-        private void populatePackageNameToApexModuleNameIfNeeded() {
-            synchronized (mLock) {
-                if (mPackageNameToApexModuleName != null) {
-                    return;
-                }
-                try {
-                    mPackageNameToApexModuleName = new ArrayMap<>();
-                    final ApexInfo[] allPkgs = mApexService.getAllPackages();
-                    for (int i = 0; i < allPkgs.length; i++) {
-                        ApexInfo ai = allPkgs[i];
-                        PackageParser.PackageLite pkgLite;
-                        try {
-                            File apexFile = new File(ai.modulePath);
-                            pkgLite = PackageParser.parsePackageLite(apexFile, 0);
-                        } catch (PackageParser.PackageParserException pe) {
-                            throw new IllegalStateException("Unable to parse: "
-                                    + ai.modulePath, pe);
-                        }
-                        mPackageNameToApexModuleName.put(pkgLite.packageName, ai.moduleName);
-                    }
-                } catch (RemoteException re) {
-                    Slog.e(TAG, "Unable to retrieve packages from apexservice: ", re);
-                    throw new RuntimeException(re);
-                }
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             }
         }
 
-        private void populateAllPackagesCacheIfNeeded() {
-            synchronized (mLock) {
-                if (mAllPackagesCache != null) {
-                    return;
-                }
-                try {
-                    mAllPackagesCache = new ArrayList<>();
-                    HashSet<String> activePackagesSet = new HashSet<>();
-                    HashSet<String> factoryPackagesSet = new HashSet<>();
-                    final ApexInfo[] allPkgs = mApexService.getAllPackages();
-                    for (ApexInfo ai : allPkgs) {
-                        // If the device is using flattened APEX, don't report any APEX
-                        // packages since they won't be managed or updated by PackageManager.
-                        if ((new File(ai.modulePath)).isDirectory()) {
-                            break;
-                        }
-                        int flags = PackageManager.GET_META_DATA
-                                | PackageManager.GET_SIGNING_CERTIFICATES
-                                | PackageManager.GET_SIGNATURES;
-                        PackageParser.Package pkg;
-                        try {
-                            File apexFile = new File(ai.modulePath);
-                            PackageParser pp = new PackageParser();
-                            pkg = pp.parsePackage(apexFile, flags, false);
-                            PackageParser.collectCertificates(pkg, false);
-                        } catch (PackageParser.PackageParserException pe) {
-                            throw new IllegalStateException("Unable to parse: " + ai, pe);
-                        }
+        @GuardedBy("mLock")
+        private void scanApexPackagesInternalLocked(PackageParser2 packageParser,
+                ExecutorService executorService) {
+            final ApexInfo[] allPkgs;
+            try {
+                mAllPackagesCache = new ArrayList<>();
+                mPackageNameToApexModuleName = new ArrayMap<>();
+                allPkgs = mApexService.getAllPackages();
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+                throw new RuntimeException(re);
+            }
+            if (allPkgs.length == 0) {
+                return;
+            }
+            int flags = PackageManager.GET_META_DATA
+                    | PackageManager.GET_SIGNING_CERTIFICATES
+                    | PackageManager.GET_SIGNATURES;
+            ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>();
+            ParallelPackageParser parallelPackageParser =
+                    new ParallelPackageParser(packageParser, executorService);
 
-                        final PackageInfo packageInfo =
-                                PackageParser.generatePackageInfo(pkg, ai, flags);
-                        mAllPackagesCache.add(packageInfo);
-                        if (ai.isActive) {
-                            if (activePackagesSet.contains(packageInfo.packageName)) {
-                                throw new IllegalStateException(
-                                        "Two active packages have the same name: "
-                                                + packageInfo.packageName);
-                            }
-                            activePackagesSet.add(packageInfo.packageName);
-                        }
-                        if (ai.isFactory) {
-                            if (factoryPackagesSet.contains(packageInfo.packageName)) {
-                                throw new IllegalStateException(
-                                        "Two factory packages have the same name: "
-                                                + packageInfo.packageName);
-                            }
-                            factoryPackagesSet.add(packageInfo.packageName);
-                        }
+            for (ApexInfo ai : allPkgs) {
+                File apexFile = new File(ai.modulePath);
+                parallelPackageParser.submit(apexFile, flags);
+                parsingApexInfo.put(apexFile, ai);
+            }
+
+            HashSet<String> activePackagesSet = new HashSet<>();
+            HashSet<String> factoryPackagesSet = new HashSet<>();
+            // Process results one by one
+            for (int i = 0; i < parsingApexInfo.size(); i++) {
+                ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
+                Throwable throwable = parseResult.throwable;
+                ApexInfo ai = parsingApexInfo.get(parseResult.scanFile);
+
+                if (throwable == null) {
+                    final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate(
+                            parseResult.parsedPackage, ai, flags);
+                    if (packageInfo == null) {
+                        throw new IllegalStateException("Unable to generate package info: "
+                                + ai.modulePath);
                     }
-                } catch (RemoteException re) {
-                    Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
-                    throw new RuntimeException(re);
+                    mAllPackagesCache.add(packageInfo);
+                    mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
+                    if (ai.isActive) {
+                        if (activePackagesSet.contains(packageInfo.packageName)) {
+                            throw new IllegalStateException(
+                                    "Two active packages have the same name: "
+                                            + packageInfo.packageName);
+                        }
+                        activePackagesSet.add(packageInfo.packageName);
+                    }
+                    if (ai.isFactory) {
+                        if (factoryPackagesSet.contains(packageInfo.packageName)) {
+                            throw new IllegalStateException(
+                                    "Two factory packages have the same name: "
+                                            + packageInfo.packageName);
+                        }
+                        factoryPackagesSet.add(packageInfo.packageName);
+                    }
+                } else if (throwable instanceof PackageParser.PackageParserException) {
+                    throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
+                } else {
+                    throw new IllegalStateException("Unexpected exception occurred while parsing "
+                            + ai.modulePath, throwable);
                 }
             }
         }
 
         @Override
-        @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
-            populateAllPackagesCacheIfNeeded();
+        @Nullable
+        public PackageInfo getPackageInfo(String packageName,
+                @PackageInfoFlags int flags) {
+            Preconditions.checkState(mAllPackagesCache != null,
+                    "APEX packages have not been scanned");
             boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
             boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
             for (PackageInfo packageInfo: mAllPackagesCache) {
@@ -525,7 +536,8 @@
 
         @Override
         List<PackageInfo> getActivePackages() {
-            populateAllPackagesCacheIfNeeded();
+            Preconditions.checkState(mAllPackagesCache != null,
+                    "APEX packages have not been scanned");
             return mAllPackagesCache
                     .stream()
                     .filter(item -> isActive(item))
@@ -534,7 +546,8 @@
 
         @Override
         List<PackageInfo> getFactoryPackages() {
-            populateAllPackagesCacheIfNeeded();
+            Preconditions.checkState(mAllPackagesCache != null,
+                    "APEX packages have not been scanned");
             return mAllPackagesCache
                     .stream()
                     .filter(item -> isFactory(item))
@@ -543,7 +556,8 @@
 
         @Override
         List<PackageInfo> getInactivePackages() {
-            populateAllPackagesCacheIfNeeded();
+            Preconditions.checkState(mAllPackagesCache != null,
+                    "APEX packages have not been scanned");
             return mAllPackagesCache
                     .stream()
                     .filter(item -> !isActive(item))
@@ -553,7 +567,8 @@
         @Override
         boolean isApexPackage(String packageName) {
             if (!isApexSupported()) return false;
-            populateAllPackagesCacheIfNeeded();
+            Preconditions.checkState(mAllPackagesCache != null,
+                    "APEX packages have not been scanned");
             for (PackageInfo packageInfo : mAllPackagesCache) {
                 if (packageInfo.packageName.equals(packageName)) {
                     return true;
@@ -563,6 +578,36 @@
         }
 
         @Override
+        @Nullable
+        public String getActiveApexPackageNameContainingPackage(
+                @NonNull AndroidPackage containedPackage) {
+            Preconditions.checkState(mPackageNameToApexModuleName != null,
+                    "APEX packages have not been scanned");
+
+            Objects.requireNonNull(containedPackage);
+
+            synchronized (mLock) {
+                int numApksInApex = mApksInApex.size();
+                for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) {
+                    if (mApksInApex.valueAt(apkInApexNum).contains(
+                            containedPackage.getPackageName())) {
+                        String apexModuleName = mApksInApex.keyAt(apkInApexNum);
+
+                        int numApexPkgs = mPackageNameToApexModuleName.size();
+                        for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) {
+                            if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals(
+                                    apexModuleName)) {
+                                return mPackageNameToApexModuleName.keyAt(apexPkgNum);
+                            }
+                        }
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        @Override
         @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
             try {
                 ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
@@ -684,8 +729,9 @@
 
         @Override
         List<String> getApksInApex(String apexPackageName) {
-            populatePackageNameToApexModuleNameIfNeeded();
             synchronized (mLock) {
+                Preconditions.checkState(mPackageNameToApexModuleName != null,
+                        "APEX packages have not been scanned");
                 String moduleName = mPackageNameToApexModuleName.get(apexPackageName);
                 if (moduleName == null) {
                     return Collections.emptyList();
@@ -697,17 +743,19 @@
         @Override
         @Nullable
         public String getApexModuleNameForPackageName(String apexPackageName) {
-            populatePackageNameToApexModuleNameIfNeeded();
             synchronized (mLock) {
+                Preconditions.checkState(mPackageNameToApexModuleName != null,
+                        "APEX packages have not been scanned");
                 return mPackageNameToApexModuleName.get(apexPackageName);
             }
         }
 
         @Override
         public long snapshotCeData(int userId, int rollbackId, String apexPackageName) {
-            populatePackageNameToApexModuleNameIfNeeded();
             String apexModuleName;
             synchronized (mLock) {
+                Preconditions.checkState(mPackageNameToApexModuleName != null,
+                        "APEX packages have not been scanned");
                 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
             }
             if (apexModuleName == null) {
@@ -724,9 +772,10 @@
 
         @Override
         public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) {
-            populatePackageNameToApexModuleNameIfNeeded();
             String apexModuleName;
             synchronized (mLock) {
+                Preconditions.checkState(mPackageNameToApexModuleName != null,
+                        "APEX packages have not been scanned");
                 apexModuleName = mPackageNameToApexModuleName.get(apexPackageName);
             }
             if (apexModuleName == null) {
@@ -797,15 +846,7 @@
         void dump(PrintWriter pw, @Nullable String packageName) {
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
             try {
-                populateAllPackagesCacheIfNeeded();
                 ipw.println();
-                ipw.println("Active APEX packages:");
-                dumpFromPackagesCache(getActivePackages(), packageName, ipw);
-                ipw.println("Inactive APEX packages:");
-                dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
-                ipw.println("Factory APEX packages:");
-                dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
-                ipw.increaseIndent();
                 ipw.println("APEX session state:");
                 ipw.increaseIndent();
                 final ApexSessionInfo[] sessions = mApexService.getSessions();
@@ -834,6 +875,17 @@
                     ipw.decreaseIndent();
                 }
                 ipw.decreaseIndent();
+                ipw.println();
+                if (mAllPackagesCache == null) {
+                    ipw.println("APEX packages have not been scanned");
+                    return;
+                }
+                ipw.println("Active APEX packages:");
+                dumpFromPackagesCache(getActivePackages(), packageName, ipw);
+                ipw.println("Inactive APEX packages:");
+                dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
+                ipw.println("Factory APEX packages:");
+                dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
             } catch (RemoteException e) {
                 ipw.println("Couldn't communicate with apexd.");
             }
@@ -879,12 +931,13 @@
         }
 
         @Override
-        void systemReady(Context context) {
+        void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
+                @NonNull ExecutorService executorService) {
             // No-op
         }
 
         @Override
-        PackageInfo getPackageInfo(String packageName, int flags) {
+        public PackageInfo getPackageInfo(String packageName, int flags) {
             return null;
         }
 
@@ -909,6 +962,15 @@
         }
 
         @Override
+        @Nullable
+        public String getActiveApexPackageNameContainingPackage(
+                @NonNull AndroidPackage containedPackage) {
+            Objects.requireNonNull(containedPackage);
+
+            return null;
+        }
+
+        @Override
         ApexSessionInfo getStagedSessionInfo(int sessionId) {
             throw new UnsupportedOperationException();
         }
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 7069818..4087675 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -64,6 +64,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
     private static final String TAG = "CrossProfileAppsService";
@@ -447,7 +448,7 @@
         final int uid = mInjector.getPackageManager()
                 .getPackageUidAsUser(packageName, /* flags= */ 0, userId);
         if (currentModeEquals(newMode, packageName, uid)) {
-            Slog.w(TAG, "Attempt to set mode to existing value of " + newMode + " for "
+            Slog.i(TAG, "Attempt to set mode to existing value of " + newMode + " for "
                     + packageName + " on user ID " + userId);
             return;
         }
@@ -577,6 +578,24 @@
         setInteractAcrossProfilesAppOp(packageName, AppOpsManager.opToDefaultMode(op));
     }
 
+    @Override
+    public void clearInteractAcrossProfilesAppOps() {
+        final int defaultMode =
+                AppOpsManager.opToDefaultMode(
+                        AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES));
+        findAllPackageNames()
+                .forEach(packageName -> setInteractAcrossProfilesAppOp(packageName, defaultMode));
+    }
+
+    private List<String> findAllPackageNames() {
+        return mInjector.getPackageManagerInternal()
+                .getInstalledApplications(
+                        /* flags= */ 0, mInjector.getCallingUserId(), mInjector.getCallingUid())
+                .stream()
+                .map(applicationInfo -> applicationInfo.packageName)
+                .collect(Collectors.toList());
+    }
+
     CrossProfileAppsInternal getLocalService() {
         return mLocalService;
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2ff3d2a..8ff7ea9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -490,6 +490,14 @@
             throw new SecurityException("User restriction prevents installing");
         }
 
+        if (params.dataLoaderParams != null
+                && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2)
+                        != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("You need the "
+                    + "com.android.permission.USE_INSTALLER_V2 permission "
+                    + "to use a data loader");
+        }
+
         String requestedInstallerPackageName = params.installerPackageName != null
                 ? params.installerPackageName : installerPackageName;
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 348a4cb..42ed206 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -2479,12 +2479,14 @@
 
     @Override
     public DataLoaderParamsParcel getDataLoaderParams() {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null;
     }
 
     @Override
     public void addFile(int location, String name, long lengthBytes, byte[] metadata,
             byte[] signature) {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
                     "Cannot add files to non-data loader installation session.");
@@ -2517,6 +2519,7 @@
 
     @Override
     public void removeFile(int location, String name) {
+        mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null);
         if (!isDataLoaderInstallation()) {
             throw new IllegalStateException(
                     "Cannot add files to non-data loader installation session.");
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4e5d6c4..34363c8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2900,6 +2900,9 @@
                     mMetrics, mCacheDir, mPackageParserCallback);
 
             ExecutorService executorService = ParallelPackageParser.makeExecutorService();
+            // Prepare apex package info before scanning APKs, these information are needed when
+            // scanning apk in apex.
+            mApexManager.scanApexPackagesTraced(packageParser, executorService);
             // Collect vendor/product/system_ext overlay packages. (Do this before scanning
             // any apps.)
             // For security and version matching reason, only consider overlay packages if they
@@ -5070,15 +5073,16 @@
      * action and a {@code android.intent.category.BROWSABLE} category</li>
      * </ul>
      */
-    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps) {
+    int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
+            boolean matchSystemOnly) {
         return updateFlagsForResolve(flags, userId, callingUid,
-                wantInstantApps, false /*onlyExposedExplicitly*/);
+                wantInstantApps, matchSystemOnly, false /*onlyExposedExplicitly*/);
     }
 
     int updateFlagsForResolve(int flags, int userId, int callingUid,
-            boolean wantInstantApps, boolean onlyExposedExplicitly) {
+            boolean wantInstantApps, boolean onlyExposedExplicitly, boolean matchSystemOnly) {
         // Safe mode means we shouldn't match any third-party components
-        if (mSafeMode) {
+        if (mSafeMode || matchSystemOnly) {
             flags |= PackageManager.MATCH_SYSTEM_ONLY;
         }
         if (getInstantAppPackageName(callingUid) != null) {
@@ -6170,7 +6174,8 @@
 
             if (!mUserManager.exists(userId)) return null;
             final int callingUid = Binder.getCallingUid();
-            flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart);
+            flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
+                    intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
             mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                     false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
 
@@ -6202,7 +6207,8 @@
         intent = updateIntentForResolve(intent);
         final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
         final int flags = updateFlagsForResolve(
-                0, userId, callingUid, false /*includeInstantApps*/);
+                0, userId, callingUid, false /*includeInstantApps*/,
+                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
         final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
                 userId);
         synchronized (mLock) {
@@ -6523,7 +6529,8 @@
                 android.provider.Settings.Global.getInt(mContext.getContentResolver(),
                         android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
         flags = updateFlagsForResolve(
-                flags, userId, callingUid, false /*includeInstantApps*/);
+                flags, userId, callingUid, false /*includeInstantApps*/,
+                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
         intent = updateIntentForResolve(intent);
         // writer
         synchronized (mLock) {
@@ -6735,7 +6742,8 @@
             }
             synchronized (mLock) {
                 int flags = updateFlagsForResolve(0, parent.id, callingUid,
-                        false /*includeInstantApps*/);
+                        false /*includeInstantApps*/,
+                        intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
                 CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
                         intent, resolvedType, flags, sourceUserId, parent.id);
                 return xpDomainInfo != null;
@@ -6821,7 +6829,8 @@
         }
 
         flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
-                comp != null || pkgName != null /*onlyExposedExplicitly*/);
+                comp != null || pkgName != null /*onlyExposedExplicitly*/,
+                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
         if (comp != null) {
             final List<ResolveInfo> list = new ArrayList<>(1);
             final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -7606,7 +7615,8 @@
             String resolvedType, int flags, int userId) {
         if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
-        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/);
+        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
+                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent activity options");
@@ -7792,7 +7802,8 @@
                 false /*requireFullPermission*/, false /*checkShell*/,
                 "query intent receivers");
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
-        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/);
+        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
+                intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -7882,7 +7893,8 @@
     private ResolveInfo resolveServiceInternal(Intent intent, String resolvedType, int flags,
             int userId, int callingUid) {
         if (!mUserManager.exists(userId)) return null;
-        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/);
+        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
+                false /* matchSystemOnly */);
         List<ResolveInfo> query = queryIntentServicesInternal(
                 intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
         if (query != null) {
@@ -7913,7 +7925,8 @@
                 false /*checkShell*/,
                 "query intent receivers");
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
-        flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps);
+        flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
+                false /* matchSystemOnly */);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -8050,7 +8063,8 @@
         if (!mUserManager.exists(userId)) return Collections.emptyList();
         final int callingUid = Binder.getCallingUid();
         final String instantAppPkgName = getInstantAppPackageName(callingUid);
-        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/);
+        flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
+                false /* matchSystemOnly */);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -20685,7 +20699,6 @@
         storage.registerListener(mStorageListener);
 
         mInstallerService.systemReady();
-        mApexManager.systemReady(mContext);
         mPackageDexOptimizer.systemReady();
 
         mInjector.getStorageManagerInternal().addExternalStoragePolicy(
@@ -24476,7 +24489,8 @@
         } else {
             synchronized (mLock) {
                 boolean manifestWhitelisted =
-                        mPackages.get(packageName).isAllowDontAutoRevokePermmissions();
+                        mPackages.get(packageName).getAutoRevokePermissions()
+                                == ApplicationInfo.AUTO_REVOKE_DISALLOWED;
                 return manifestWhitelisted;
             }
         }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 3cc10d1..5a1e8e2 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -230,6 +230,10 @@
             info.sharedLibraryInfos = usesLibraryInfos.isEmpty() ? null : usesLibraryInfos;
         }
 
+        info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
+        info.primaryCpuAbi = AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting);
+        info.secondaryCpuAbi = AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting);
+
         info.flags |= appInfoFlags(pkg, pkgSetting);
         info.privateFlags |= appInfoPrivateFlags(pkg, pkgSetting);
         return info;
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 79d0c2d..765ecb9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -21,6 +21,8 @@
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
+import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
 import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
@@ -40,6 +42,7 @@
 import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED;
 import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED;
 
+import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
 import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS;
@@ -128,6 +131,7 @@
 import com.android.server.ServiceThread;
 import com.android.server.SystemConfig;
 import com.android.server.Watchdog;
+import com.android.server.pm.ApexManager;
 import com.android.server.pm.PackageManagerServiceUtils;
 import com.android.server.pm.PackageSetting;
 import com.android.server.pm.SharedUserSetting;
@@ -3238,31 +3242,25 @@
 
     @Override
     public List<String> getAutoRevokeExemptionRequestedPackages(int userId) {
-        mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
-                "Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
-
-        List<String> result = new ArrayList<>();
-        mPackageManagerInt.forEachInstalledPackage(pkg -> {
-            if (pkg.isDontAutoRevokePermmissions()) {
-                result.add(pkg.getPackageName());
-            }
-        }, userId);
-
-        return result;
+        return getPackagesWithAutoRevokePolicy(AUTO_REVOKE_DISCOURAGED, userId);
     }
 
     @Override
     public List<String> getAutoRevokeExemptionGrantedPackages(int userId) {
+        return getPackagesWithAutoRevokePolicy(AUTO_REVOKE_DISALLOWED, userId);
+    }
+
+    @NonNull
+    private List<String> getPackagesWithAutoRevokePolicy(int autoRevokePolicy, int userId) {
         mContext.enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
                 "Must hold " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
 
         List<String> result = new ArrayList<>();
         mPackageManagerInt.forEachInstalledPackage(pkg -> {
-            if (pkg.isAllowDontAutoRevokePermmissions()) {
+            if (pkg.getAutoRevokePermissions() == autoRevokePolicy) {
                 result.add(pkg.getPackageName());
             }
         }, userId);
-
         return result;
     }
 
@@ -3321,8 +3319,16 @@
         if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged()
                 && !platformPackage && platformPermission) {
             if (!hasPrivappWhitelistEntry(perm, pkg)) {
-                // Only report violations for apps on system image
-                if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) {
+                ApexManager apexMgr = ApexManager.getInstance();
+                String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg);
+
+                // Only enforce whitelist this on boot
+                if (!mSystemReady
+                        // Updated system apps do not need to be whitelisted
+                        && !pkgSetting.getPkgState().isUpdatedSystemApp()
+                        // Apps that are in updated apexs' do not need to be whitelisted
+                        && (apexContainingPkg == null || apexMgr.isFactory(
+                        apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) {
                     // it's only a reportable violation if the permission isn't explicitly denied
                     ArraySet<String> deniedPermissions = null;
                     if (pkg.isVendor()) {
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 161f304..27288d8 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -30,6 +30,7 @@
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
 import android.app.AppOpsManagerInternal;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -47,6 +48,7 @@
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.permission.PermissionControllerManager;
+import android.provider.Settings;
 import android.provider.Telephony;
 import android.telecom.TelecomManager;
 import android.util.ArrayMap;
@@ -70,7 +72,9 @@
 import com.android.server.policy.PermissionPolicyInternal.OnInitializedCallback;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
 /**
@@ -180,8 +184,6 @@
         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         intentFilter.addDataScheme("package");
 
-
-        /* TODO ntmyren: enable receiver when test flakes are fixed
         getContext().registerReceiverAsUser(new BroadcastReceiver() {
             final List<Integer> mUserSetupUids = new ArrayList<>(200);
             final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
@@ -232,7 +234,6 @@
                 manager.updateUserSensitiveForApp(uid);
             }
         }, UserHandle.ALL, intentFilter, null, null);
-         */
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
index 39aeafc..d6c48a0 100644
--- a/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
+++ b/services/core/java/com/android/server/policy/SoftRestrictedPermissionPolicy.java
@@ -26,6 +26,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.storage.StorageManager.PROP_LEGACY_OP_STICKY;
 
 import static java.lang.Integer.min;
 
@@ -36,6 +37,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManagerInternal;
 
@@ -63,6 +65,9 @@
                 }
             };
 
+    private static final boolean isLegacyStorageAppOpStickyGlobal = SystemProperties.getBoolean(
+            PROP_LEGACY_OP_STICKY, /*defaultValue*/true);
+
     /**
      * TargetSDK is per package. To make sure two apps int the same shared UID do not fight over
      * what to set, always compute the combined targetSDK.
@@ -136,9 +141,12 @@
                     shouldPreserveLegacyExternalStorage = pkg.hasPreserveLegacyExternalStorage()
                             && smInternal.hasLegacyExternalStorage(appInfo.uid);
                     targetSDK = getMinimumTargetSDK(context, appInfo, user);
+                    // LEGACY_STORAGE op is normally sticky for apps targetig <= Q.
+                    // However, this device can be configured to make it non-sticky.
+                    boolean isLegacyAppOpSticky = isLegacyStorageAppOpStickyGlobal
+                            && targetSDK <= Build.VERSION_CODES.Q;
                     shouldApplyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0
-                            || (targetSDK > Build.VERSION_CODES.Q
-                            && !shouldPreserveLegacyExternalStorage);
+                            || (!isLegacyAppOpSticky && !shouldPreserveLegacyExternalStorage);
                 } else {
                     isWhiteListed = false;
                     shouldApplyRestriction = false;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5025835..86ff926 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3531,7 +3531,9 @@
         }
 
         // Control light outside of lock.
-        light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+        if (light != null) {
+            light.setFlashing(color, LogicalLight.LIGHT_FLASH_HARDWARE, (on ? 3 : 0), 0);
+        }
     }
 
     private void setDozeAfterScreenOffInternal(boolean on) {
diff --git a/services/core/java/com/android/server/power/TEST_MAPPING b/services/core/java/com/android/server/power/TEST_MAPPING
index acf3f79..74958b6 100644
--- a/services/core/java/com/android/server/power/TEST_MAPPING
+++ b/services/core/java/com/android/server/power/TEST_MAPPING
@@ -3,6 +3,7 @@
     {
       "name": "CtsBatterySavingTestCases",
       "options": [
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.LargeTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
@@ -11,6 +12,7 @@
       "name": "FrameworksMockingServicesTests",
       "options": [
         {"include-filter": "com.android.server.power"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"}
       ]
     },
@@ -18,6 +20,7 @@
       "name": "FrameworksServicesTests",
       "options": [
         {"include-filter": "com.android.server.power"},
+        {"exclude-annotation": "android.platform.test.annotations.FlakyTest"},
         {"exclude-annotation": "androidx.test.filters.FlakyTest"},
         {
           "exclude-filter": "com.android.server.power.PowerManagerServiceTest#testWakefulnessAwake_ShouldWakeUpWhenPluggedIn"
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 74c3a9e..2783d0b 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -767,7 +767,7 @@
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
-                    mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService();
+                    mThermalHal10 = android.hardware.thermal.V1_0.IThermal.getService(true);
                     mThermalHal10.linkToDeath(new DeathRecipient(),
                             THERMAL_HAL_DEATH_COOKIE);
                     Slog.i(TAG,
@@ -902,7 +902,7 @@
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
-                    mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+                    mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService(true);
                     mThermalHal11.linkToDeath(new DeathRecipient(),
                             THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal11.registerThermalCallback(mThermalCallback11);
@@ -1046,7 +1046,7 @@
         protected boolean connectToHal() {
             synchronized (mHalLock) {
                 try {
-                    mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+                    mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService(true);
                     mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
                     mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
                             0 /* not used */);
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index a83ba97..a9e8d3f 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -34,6 +34,7 @@
 import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
 import android.media.soundtrigger_middleware.Status;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
@@ -139,6 +140,14 @@
             throw new ServiceSpecificException(((RecoverableException) e).errorCode,
                     e.getMessage());
         }
+
+        /* Throwing an exception is not enough in this case. When the HAL behaves unexpectedly, the
+           system service and the HAL must be reset and the client must be notified. Without a full
+           reset in this catastrophic case, the state of the HAL and the system service cannot be
+           guaranteed to the client.
+         */
+        Log.wtf(TAG, "Crashing system server due to unrecoverable exception", e);
+        Process.killProcess(Process.myPid());
         throw new InternalServerError(e);
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index b051bab..8ff2a1b 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -37,9 +37,9 @@
         }
 
         switch (cmd) {
-            case "suggestTelephonyTimeZone":
+            case "suggest_telephony_time_zone":
                 return runSuggestTelephonyTimeZone();
-            case "suggestManualTimeZone":
+            case "suggest_manual_time_zone":
                 return runSuggestManualTimeZone();
             default: {
                 return handleDefaultCommands(cmd);
@@ -105,9 +105,9 @@
         pw.println("Time Zone Detector (time_zone_detector) commands:");
         pw.println("  help");
         pw.println("    Print this help text.");
-        pw.println("  suggestTelephonyTimeZone");
+        pw.println("  suggest_telephony_time_zone");
         pw.println("    --suggestion <telephony suggestion opts>");
-        pw.println("  suggestManualTimeZone");
+        pw.println("  suggest_manual_time_zone");
         pw.println("    --suggestion <manual suggestion opts>");
         pw.println();
         ManualTimeZoneSuggestion.printCommandLineOpts(pw);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 722d9f7..ddf166e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2441,9 +2441,8 @@
              * the caller here writes new bitmap data.
              */
             if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
-                if (DEBUG) {
-                    Slog.i(TAG, "Migrating system->lock to preserve");
-                }
+                Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+                        + "updating system wallpaper");
                 migrateSystemToLockWallpaperLocked(userId);
             }
 
@@ -2511,6 +2510,8 @@
             ParcelFileDescriptor fd = ParcelFileDescriptor.open(wallpaper.wallpaperFile,
                     MODE_CREATE|MODE_READ_WRITE|MODE_TRUNCATE);
             if (!SELinux.restorecon(wallpaper.wallpaperFile)) {
+                Slog.w(TAG, "restorecon failed for wallpaper file: " +
+                        wallpaper.wallpaperFile.getPath());
                 return null;
             }
             wallpaper.name = name;
@@ -2520,10 +2521,8 @@
             }
             // Nullify field to require new computation
             wallpaper.primaryColors = null;
-            if (DEBUG) {
-                Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
-                        + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
-            }
+            Slog.v(TAG, "updateWallpaperBitmapLocked() : id=" + wallpaper.wallpaperId
+                    + " name=" + name + " file=" + wallpaper.wallpaperFile.getName());
             return fd;
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "Error setting wallpaper", e);
@@ -2556,7 +2555,7 @@
         WallpaperData wallpaper;
 
         synchronized (mLock) {
-            if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+            Slog.v(TAG, "setWallpaperComponent name=" + name);
             wallpaper = mWallpaperMap.get(userId);
             if (wallpaper == null) {
                 throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
@@ -2571,6 +2570,8 @@
                 if (mLockWallpaperMap.get(userId) == null) {
                     // We're using the static imagery and there is no lock-specific image in place,
                     // therefore it's a shared system+lock image that we need to migrate.
+                    Slog.i(TAG, "Migrating current wallpaper to be lock-only before"
+                            + "updating system wallpaper");
                     migrateSystemToLockWallpaperLocked(userId);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6d53786..2f814f5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2085,7 +2085,7 @@
 
     /** Returns true if this activity is opaque and fills the entire space of this task. */
     boolean occludesParent() {
-        return mOccludesParent;
+        return !finishing && mOccludesParent;
     }
 
     boolean setOccludesParent(boolean occludesParent) {
@@ -4618,6 +4618,9 @@
             } catch (Exception e) {
                 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
             }
+            // The activity may be waiting for stop, but that is no longer appropriate if we are
+            // starting the activity again
+            mStackSupervisor.mStoppingActivities.remove(this);
         }
         return false;
     }
@@ -4667,7 +4670,7 @@
      * and {@link #shouldPauseActivity(ActivityRecord)}.
      */
     private boolean shouldStartActivity() {
-        return mVisibleRequested && isState(STOPPED);
+        return mVisibleRequested && (isState(STOPPED) || isState(STOPPING));
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index e8bfe8e..9089859 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -36,7 +36,6 @@
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
@@ -303,9 +302,6 @@
 
     private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
 
-    // TODO(task-hierarchy): remove when tiles can be actual parents
-    TaskTile mTile = null;
-
     private final Handler mHandler;
 
     private class ActivityStackHandler extends Handler {
@@ -551,10 +547,10 @@
     }
 
     ActivityStack(ActivityTaskManagerService atmService, int id, int activityType,
-            ActivityInfo info, Intent intent) {
+            ActivityInfo info, Intent intent, boolean createdByOrganizer) {
         this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
                 null /*taskDescription*/, null /*stack*/);
-
+        mCreatedByOrganizer = createdByOrganizer;
         setActivityType(activityType);
     }
 
@@ -601,20 +597,11 @@
     }
 
     @Override
-    public void resolveTileOverrideConfiguration(Configuration newParentConfig) {
-        super.resolveTileOverrideConfiguration(newParentConfig);
-        if (mTile != null) {
-            // If this is a virtual child of a tile, simulate the parent-child relationship
-            mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
-        }
-    }
-
-    @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         // Calling Task#onConfigurationChanged() for leaf task since the ops in this method are
         // particularly for ActivityStack, like preventing bounds changes when inheriting certain
         // windowing mode.
-        if (!isRootTask() || this instanceof TaskTile) {
+        if (!isRootTask()) {
             super.onConfigurationChanged(newParentConfig);
             return;
         }
@@ -689,6 +676,9 @@
 
     @Override
     public void setWindowingMode(int windowingMode) {
+        // Reset the cached result of toString()
+        stringName = null;
+
         // Calling Task#setWindowingMode() for leaf task since this is the a specialization of
         // {@link #setWindowingMode(int)} for ActivityStack.
         if (!isRootTask()) {
@@ -742,7 +732,6 @@
         final int currentOverrideMode = getRequestedOverrideWindowingMode();
         final DisplayContent display = getDisplay();
         final Task topTask = getTopMostTask();
-        final ActivityStack splitScreenStack = display.getRootSplitScreenPrimaryTask();
         int windowingMode = preferredWindowingMode;
         if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
                 && isTransientWindowingMode(currentMode)) {
@@ -756,14 +745,14 @@
             windowingMode = display.validateWindowingMode(windowingMode,
                     null /* ActivityRecord */, topTask, getActivityType());
         }
-        if (splitScreenStack == this
+        if (display.getRootSplitScreenPrimaryTask() == this
                 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
             // Resolution to split-screen secondary for the primary split-screen stack means
             // we want to leave split-screen mode.
             windowingMode = mRestoreOverrideWindowingMode;
         }
 
-        final boolean alreadyInSplitScreenMode = display.hasSplitScreenPrimaryTask();
+        final boolean alreadyInSplitScreenMode = display.isSplitScreenModeActivated();
 
         // Don't send non-resizeable notifications if the windowing mode changed was a side effect
         // of us entering split-screen mode.
@@ -831,7 +820,7 @@
                 return;
             }
 
-            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && splitScreenStack != null) {
+            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && alreadyInSplitScreenMode) {
                 // We already have a split-screen stack in this display, so just move the tasks over.
                 // TODO: Figure-out how to do all the stuff in
                 // AMS.setTaskWindowingModeSplitScreenPrimary
@@ -1063,7 +1052,7 @@
         final DisplayContent display = getDisplay();
 
         if (inSplitScreenSecondaryWindowingMode()) {
-            // If the stack is in split-screen seconardy mode, we need to make sure we move the
+            // If the stack is in split-screen secondary mode, we need to make sure we move the
             // primary split-screen stack forward in the case it is currently behind a fullscreen
             // stack so both halves of the split-screen appear on-top and the fullscreen stack isn't
             // cutting between them.
@@ -1085,12 +1074,13 @@
             display.moveHomeStackToFront(reason + " returnToHome");
         }
 
-        final boolean movingTask = task != null;
-        display.positionStackAtTop(this, !movingTask /* includingParents */, reason);
-        if (movingTask) {
-            // This also moves the entire hierarchy branch to top, including parents
-            positionChildAtTop(task);
+        if (isRootTask()) {
+            display.positionStackAtTop(this, false /* includingParents */, reason);
         }
+        if (task == null) {
+            task = this;
+        }
+        task.getParent().positionChildAt(POSITION_TOP, task, true /* includingParents */);
     }
 
     /**
@@ -1116,12 +1106,6 @@
         }
     }
 
-    @Override
-    boolean isFocusable() {
-        // Special check for tile which isn't really in the hierarchy
-        return mTile != null ? mTile.isFocusable() : super.isFocusable();
-    }
-
     boolean isTopActivityFocusable() {
         final ActivityRecord r = topRunningActivity();
         return r != null ? r.isFocusable()
@@ -2358,8 +2342,7 @@
         if (!newTask && isOrhasTask) {
             // Starting activity cannot be occluding activity, otherwise starting window could be
             // remove immediately without transferring to starting activity.
-            final ActivityRecord occludingActivity = getActivity(
-                    (ar) -> !ar.finishing && ar.occludesParent(), true, r);
+            final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
             if (occludingActivity != null) {
                 // Here it is!  Now, if this is not yet visible (occluded by another task) to the
                 // user, then just add it without starting; it will get started when the user
@@ -2588,6 +2571,13 @@
         if (r == null || r.app != app) {
             return null;
         }
+        if (r.isActivityTypeHome() && mAtmService.mHomeProcess == app) {
+            // Home activities should not be force-finished as we have nothing else to go
+            // back to. AppErrors will get to it after two crashes in MIN_CRASH_INTERVAL.
+            Slog.w(TAG, "  Not force finishing home activity "
+                    + r.intent.getComponent().flattenToShortString());
+            return null;
+        }
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
         Task finishedTask = r.getTask();
@@ -3078,6 +3068,14 @@
         task.setOverrideDisplayedBounds(bounds == null || bounds.isEmpty() ? null : bounds);
     }
 
+    /**
+     * Returns the top-most activity that occludes the given one, or @{code null} if none.
+     */
+    @Nullable
+    private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) {
+        return getActivity((ar) -> ar.occludesParent(), true /* traverseTopToBottom */, activity);
+    }
+
     boolean willActivityBeVisible(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (r == null) {
@@ -3085,9 +3083,7 @@
         }
 
         // See if there is an occluding activity on-top of this one.
-        final ActivityRecord occludingActivity = getActivity((ar) ->
-                ar.occludesParent() && !ar.finishing,
-                r, false /*includeBoundary*/, true /*traverseTopToBottom*/);
+        final ActivityRecord occludingActivity = getOccludingActivityAbove(r);
         if (occludingActivity != null) return false;
 
         if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false,"
@@ -3542,6 +3538,10 @@
 
     @Override
     void onChildPositionChanged(WindowContainer child) {
+        if (isOrganized()) {
+            mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */);
+        }
+
         if (!mChildren.contains(child)) {
             return;
         }
@@ -3572,11 +3572,6 @@
         if (oldDisplay != null && oldDisplay.isRemoving()) {
             postReparent();
         }
-        if (mTile != null && getSurfaceControl() != null) {
-            // by now, the TaskStack should already have been reparented, so we can reparent its
-            // surface here
-            reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
-        }
     }
 
     void reparent(DisplayContent newParent, boolean onTop) {
@@ -3614,16 +3609,7 @@
 
     @Override
     void getRelativeDisplayedPosition(Point outPos) {
-        // check for tile which is "virtually" a parent.
-        if (mTile != null) {
-            final Rect dispBounds = getDisplayedBounds();
-            outPos.set(dispBounds.left, dispBounds.top);
-            final Rect parentBounds = mTile.getBounds();
-            outPos.offset(-parentBounds.left, -parentBounds.top);
-        } else {
-            super.getRelativeDisplayedPosition(outPos);
-        }
-
+        super.getRelativeDisplayedPosition(outPos);
         final int outset = getStackOutset();
         outPos.x -= outset;
         outPos.y -= outset;
@@ -3633,16 +3619,6 @@
         if (mSurfaceControl == null) {
             return;
         }
-        if (mTile != null) {
-            // Tile controls crop, so the app needs to be able to draw its background outside of
-            // the stack bounds for when the tile crop gets bigger than the stack.
-            if (mLastSurfaceSize.equals(0, 0)) {
-                return;
-            }
-            transaction.setWindowCrop(mSurfaceControl, null);
-            mLastSurfaceSize.set(0, 0);
-            return;
-        }
 
         final Rect stackBounds = getDisplayedBounds();
         int width = stackBounds.width();
@@ -3666,9 +3642,6 @@
 
     @Override
     void onDisplayChanged(DisplayContent dc) {
-        if (mTile != null && dc != mTile.getDisplay()) {
-            mTile.removeChild(this);
-        }
         super.onDisplayChanged(dc);
         if (isRootTask()) {
             updateSurfaceBounds();
@@ -3781,20 +3754,6 @@
         return super.checkCompleteDeferredRemoval();
     }
 
-    @Override
-    int getOrientation() {
-        return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
-    }
-
-    private boolean canSpecifyOrientation() {
-        final int windowingMode = getWindowingMode();
-        final int activityType = getActivityType();
-        return windowingMode == WINDOWING_MODE_FULLSCREEN
-                || activityType == ACTIVITY_TYPE_HOME
-                || activityType == ACTIVITY_TYPE_RECENTS
-                || activityType == ACTIVITY_TYPE_ASSISTANT;
-    }
-
     public DisplayInfo getDisplayInfo() {
         return mDisplayContent.getDisplayInfo();
     }
@@ -3825,49 +3784,6 @@
         return shouldSleepActivities() || mAtmService.mShuttingDown;
     }
 
-    TaskTile getTile() {
-        return mTile;
-    }
-
-    /**
-     * Don't call this directly. instead use {@link TaskTile#addChild} or
-     * {@link TaskTile#removeChild}.
-     */
-    void setTile(TaskTile tile) {
-        TaskTile origTile = mTile;
-        mTile = tile;
-        final ConfigurationContainer parent = getParent();
-        if (parent != null) {
-            onConfigurationChanged(parent.getConfiguration());
-        }
-
-        // Reparent to tile surface or back to original parent
-        if (getSurfaceControl() == null) {
-            return;
-        }
-        if (mTile != null) {
-            // don't use reparentSurfaceControl because we need to bypass taskorg check
-            mSurfaceAnimator.reparent(getPendingTransaction(), mTile.getSurfaceControl());
-        } else if (mTile == null && origTile != null) {
-            mSurfaceAnimator.reparent(getPendingTransaction(), getParentSurfaceControl());
-        }
-    }
-
-    @Override
-    public SurfaceControl getParentSurfaceControl() {
-        // Tile is a "virtual" parent, so we need to intercept the parent surface here
-        return mTile != null ? mTile.getSurfaceControl() : super.getParentSurfaceControl();
-    }
-
-    @Override
-    void removeImmediately() {
-        // TODO(task-hierarchy): remove this override when tiles are in hierarchy
-        if (mTile != null) {
-            mTile.removeChild(this);
-        }
-        super.removeImmediately();
-    }
-
     @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
@@ -3912,7 +3828,7 @@
             proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
         }
 
-        proto.write(CREATED_BY_ORGANIZER, this instanceof TaskTile);
+        proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
 
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 57f357d..4652f49 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -423,6 +423,10 @@
 
             final ActivityStack toStack = mToDisplay.getOrCreateStack(
                     null, mTmpOptions, task, task.getActivityType(), mOnTop);
+            if (task == toStack) {
+                // The task was reused as the root task.
+                return;
+            }
 
             if (mOnTop) {
                 final boolean isTopTask = task == mTopTask;
@@ -1704,7 +1708,7 @@
                 mRootWindowContainer.getLaunchStack(null, aOptions, task, onTop);
         final WindowContainer parent = task.getParent();
 
-        if (parent == stack) {
+        if (parent == stack || task == stack) {
             // Nothing else to do since it is already restored in the right stack.
             return true;
         }
@@ -2237,7 +2241,7 @@
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
         final boolean inSplitScreenMode = actualStack != null
-                && actualStack.getDisplay().hasSplitScreenPrimaryTask();
+                && actualStack.getDisplay().isSplitScreenModeActivated();
         if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
                 && !isSecondaryDisplayPreferred) || !task.isActivityTypeStandardOrUndefined()) {
             return;
@@ -2284,16 +2288,14 @@
         if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
             // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
             // we need to move it to top of fullscreen stack, otherwise it will be covered.
-
-            final ActivityStack dockedStack =
-                    task.getStack().getDisplay().getRootSplitScreenPrimaryTask();
-            if (dockedStack != null) {
+            final DisplayContent display = task.getStack().getDisplay();
+            if (display.isSplitScreenModeActivated()) {
                 // Display a warning toast that we tried to put an app that doesn't support
                 // split-screen in split-screen.
                 mService.getTaskChangeNotificationController()
                         .notifyActivityDismissingDockedStack();
-                dockedStack.getDisplay().onSplitScreenModeDismissed();
-                dockedStack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+                display.onSplitScreenModeDismissed();
+                display.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
                         true /* notifyClients */);
             }
             return;
@@ -2602,7 +2604,7 @@
                         "startActivityFromRecents: Task " + taskId + " not found.");
             } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                     && task.getWindowingMode() != windowingMode) {
-                mService.moveTaskToSplitScreenPrimaryTile(task, true /* toTop */);
+                mService.moveTaskToSplitScreenPrimaryTask(task, true /* toTop */);
             }
 
             if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 14ca7cb..da1c045 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -30,7 +30,6 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WaitResult.LAUNCH_STATE_COLD;
 import static android.app.WaitResult.LAUNCH_STATE_HOT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -78,6 +77,7 @@
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
 import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -1566,7 +1566,7 @@
         }
 
         if (!mAvoidMoveToFront && mDoResume) {
-            mTargetStack.moveToFront("reuseOrNewTask");
+            mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
             if (mOptions != null) {
                 if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED) {
                     mTargetStack.setWindowingMode(mPreferredWindowingMode);
@@ -2364,6 +2364,7 @@
     private void setTargetStackIfNeeded(ActivityRecord intentActivity) {
         mTargetStack = intentActivity.getRootTask();
         mTargetStack.mLastPausedActivity = null;
+        Task intentTask = intentActivity.getTask();
         // If the target task is not in the front, then we need to bring it to the front...
         // except...  well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
         // the same behavior as if a new instance was being started, which means not bringing it
@@ -2374,7 +2375,7 @@
             final ActivityRecord curTop = (focusStack == null)
                     ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
             final Task topTask = curTop != null ? curTop.getTask() : null;
-            differentTopTask = topTask != intentActivity.getTask()
+            differentTopTask = topTask != intentTask
                     || (focusStack != null && topTask != focusStack.getTopMostTask());
         } else {
             // The existing task should always be different from those in other displays.
@@ -2391,7 +2392,6 @@
                     intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
                 }
 
-                final Task intentTask = intentActivity.getTask();
                 final ActivityStack launchStack =
                         getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions);
                 if (launchStack == null || launchStack == mTargetStack) {
@@ -2400,6 +2400,14 @@
                     // new intent has delivered.
                     final boolean isSplitScreenTopStack = mTargetStack.isTopSplitScreenStack();
 
+                    // TODO(b/151572268): Figure out a better way to move tasks in above 2-levels
+                    //  tasks hierarchies.
+                    if (mTargetStack != intentTask
+                            && mTargetStack != intentTask.getParent().asTask()) {
+                        intentTask.getParent().positionChildAt(POSITION_TOP, intentTask,
+                                false /* includingParents */);
+                        intentTask = intentTask.getParent().asTask();
+                    }
                     // We only want to move to the front, if we aren't going to launch on a
                     // different stack. If we launch on a different stack, we will put the
                     // task on top there.
@@ -2420,8 +2428,8 @@
         // Need to update mTargetStack because if task was moved out of it, the original stack may
         // be destroyed.
         mTargetStack = intentActivity.getRootTask();
-        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
-                WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
+        mSupervisor.handleNonResizableTaskIfNeeded(intentTask, WINDOWING_MODE_UNDEFINED,
+                DEFAULT_DISPLAY, mTargetStack);
     }
 
     private void resumeTargetStackIfNeeded() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 214a676..bf92542 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -31,12 +31,11 @@
 import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -122,6 +121,7 @@
 import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
 import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -144,7 +144,6 @@
 import android.app.IAssistDataReceiver;
 import android.app.INotificationManager;
 import android.app.IRequestFinishCallback;
-import android.window.ITaskOrganizerController;
 import android.app.ITaskStackListener;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -230,9 +229,9 @@
 import android.view.IRecentsAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
+import android.view.WindowManager;
 import android.window.IWindowOrganizerController;
 import android.window.WindowContainerTransaction;
-import android.view.WindowManager;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
@@ -1274,9 +1273,13 @@
         a.colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
         a.flags |= ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
 
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchActivityType(ACTIVITY_TYPE_DREAM);
+
         try {
             getActivityStartController().obtainStarter(intent, "dream")
                     .setActivityInfo(a)
+                    .setActivityOptions(options.toBundle())
                     .setIsDream(true)
                     .execute();
             return true;
@@ -2349,16 +2352,18 @@
                 }
 
                 final ActivityStack stack = task.getStack();
-                // Convert some windowing-mode changes into root-task reparents for split-screen.
-                if (stack.getTile() != null) {
-                    stack.getDisplay().onSplitScreenModeDismissed();
-                }
                 if (toTop) {
                     stack.moveToFront("setTaskWindowingMode", task);
                 }
-                stack.setWindowingMode(windowingMode);
-                stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
-                        true /* notifyClients */);
+                // Convert some windowing-mode changes into root-task reparents for split-screen.
+                if (stack.inSplitScreenWindowingMode()) {
+                    stack.getDisplay().onSplitScreenModeDismissed();
+
+                } else {
+                    stack.setWindowingMode(windowingMode);
+                    stack.getDisplay().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS,
+                            true /* notifyClients */);
+                }
                 return true;
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -2609,13 +2614,16 @@
 
     @Override
     public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) {
-        return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED);
+        return getFilteredTasks(maxNum, false /* filterForVisibleRecents */);
     }
 
+    /**
+     * @param filterOnlyVisibleRecents whether to filter the tasks based on whether they would ever
+     *                                 be visible in the recent task list in systemui
+     */
     @Override
     public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum,
-            @WindowConfiguration.ActivityType int ignoreActivityType,
-            @WindowConfiguration.WindowingMode int ignoreWindowingMode) {
+            boolean filterOnlyVisibleRecents) {
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         final boolean crossUser = isCrossUserAllowed(callingPid, callingUid);
@@ -2631,8 +2639,8 @@
             if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum);
 
             final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid);
-            mRootWindowContainer.getRunningTasks(maxNum, list, ignoreActivityType,
-                    ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds);
+            mRootWindowContainer.getRunningTasks(maxNum, list, filterOnlyVisibleRecents, callingUid,
+                    allowed, crossUser, callingProfileIds);
         }
 
         return list;
@@ -2755,24 +2763,22 @@
         }
 
         final int prevMode = task.getWindowingMode();
-        moveTaskToSplitScreenPrimaryTile(task, toTop);
+        moveTaskToSplitScreenPrimaryTask(task, toTop);
         return prevMode != task.getWindowingMode();
     }
 
-    void moveTaskToSplitScreenPrimaryTile(Task task, boolean toTop) {
-        ActivityStack stack = task.getStack();
-        TaskTile tile = null;
-        for (int i = stack.getDisplay().getStackCount() - 1; i >= 0; --i) {
-            tile = stack.getDisplay().getStackAt(i).asTile();
-            if (tile != null && tile.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                break;
-            }
+    void moveTaskToSplitScreenPrimaryTask(Task task, boolean toTop) {
+        final DisplayContent display = task.getDisplayContent();
+        final ActivityStack primarySplitTask = display.getRootSplitScreenPrimaryTask();
+        if (primarySplitTask == null) {
+            throw new IllegalStateException("Can't enter split without associated organized task");
         }
-        if (tile == null) {
-            throw new IllegalStateException("Can't enter split without associated tile");
+
+        if (toTop) {
+            display.positionStackAt(POSITION_TOP, primarySplitTask, false /* includingParents */);
         }
         WindowContainerTransaction wct = new WindowContainerTransaction();
-        wct.reparent(stack.mRemoteToken, tile.mRemoteToken, toTop);
+        wct.reparent(task.getStack().mRemoteToken, primarySplitTask.mRemoteToken, toTop);
         mWindowOrganizerController.applyTransaction(wct);
     }
 
@@ -3239,7 +3245,8 @@
 
                 final ActivityStack stack = r.getRootTask();
                 final Task task = stack.getDisplay().createStack(stack.getWindowingMode(),
-                        stack.getActivityType(), !ON_TOP, ainfo, intent);
+                        stack.getActivityType(), !ON_TOP, ainfo, intent,
+                        false /* createdByOrganizer */);
 
                 if (!mRecentTasks.addToBottom(task)) {
                     // The app has too many tasks already and we can't add any more
@@ -4278,19 +4285,9 @@
         try {
             synchronized (mGlobalLock) {
                 final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
-                TaskTile primary = null;
-                TaskTile secondary = null;
-                for (int i = dc.getStackCount() - 1; i >= 0; --i) {
-                    final TaskTile t = dc.getStackAt(i).asTile();
-                    if (t == null) {
-                        continue;
-                    }
-                    if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                        primary = t;
-                    } else if (t.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
-                        secondary = t;
-                    }
-                }
+                final Task primary = dc.getRootSplitScreenPrimaryTask();
+                final Task secondary = dc.getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+                        && t.inSplitScreenSecondaryWindowingMode());
                 if (primary == null || secondary == null) {
                     return;
                 }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 6a47c9e..654ccc8 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -618,6 +618,7 @@
                 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
                         (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
                 if (anim != null) {
+                    anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
                     mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 33dd9cf..1036af6 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -467,6 +468,10 @@
         return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
     }
 
+    public boolean isActivityTypeDream() {
+        return getActivityType() == ACTIVITY_TYPE_DREAM;
+    }
+
     public boolean isActivityTypeStandard() {
         return getActivityType() == ACTIVITY_TYPE_STANDARD;
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7df731b..a90016a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -200,7 +200,6 @@
 import android.view.Gravity;
 import android.view.IDisplayWindowInsetsController;
 import android.view.ISystemGestureExclusionListener;
-import android.window.ITaskOrganizer;
 import android.view.IWindow;
 import android.view.InputChannel;
 import android.view.InputDevice;
@@ -217,6 +216,7 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.window.WindowContainerTransaction;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
@@ -456,6 +456,8 @@
 
     private final Configuration mTmpConfiguration = new Configuration();
 
+    private ArrayList<Task> mTmpTasks = new ArrayList<>();
+
     /** Remove this display when animation on it has completed. */
     private boolean mDeferredRemoval;
 
@@ -654,8 +656,11 @@
     private final RootWindowContainer.FindTaskResult
             mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
 
-    // When non-null, new stacks get put into this tile.
-    TaskTile mLaunchTile = null;
+    // When non-null, new tasks get put into this root task.
+    Task mLaunchRootTask = null;
+
+    // Used in performing layout
+    private boolean mTmpWindowsBehindIme;
 
     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
         WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -748,6 +753,12 @@
                     + " parentHidden=" + w.isParentWindowHidden());
         }
 
+        // Sets mBehindIme for each window. Windows behind IME can get IME insets.
+        w.mBehindIme = mTmpWindowsBehindIme;
+        if (w == mInputMethodWindow) {
+            mTmpWindowsBehindIme = true;
+        }
+
         // If this view is GONE, then skip it -- keep the current frame, and let the caller know
         // so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,
         // since that means "perform layout as normal, just don't display").
@@ -1306,8 +1317,6 @@
         if (mDisplayRotation.isWaitingForRemoteRotation()) {
             return;
         }
-        // Clear the record because the display will sync to current rotation.
-        mFixedRotationLaunchingApp = null;
 
         final boolean configUpdated = updateDisplayOverrideConfigurationLocked();
         if (configUpdated) {
@@ -1498,7 +1507,7 @@
         startFixedRotationTransform(r, rotation);
         mAppTransition.registerListenerLocked(new WindowManagerInternal.AppTransitionListener() {
             void done() {
-                r.clearFixedRotationTransform();
+                r.finishFixedRotationTransform();
                 mAppTransition.unregisterListener(this);
             }
 
@@ -1527,7 +1536,8 @@
         if (token != mFixedRotationLaunchingApp) {
             return false;
         }
-        if (updateOrientation()) {
+        // Update directly because the app which will change the orientation of display is ready.
+        if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
             sendNewConfiguration();
             return true;
         }
@@ -1573,7 +1583,7 @@
      * @param oldRotation the rotation we are coming from.
      * @param rotation the rotation to apply.
      */
-    void applyRotationLocked(final int oldRotation, final int rotation) {
+    private void applyRotation(final int oldRotation, final int rotation) {
         mDisplayRotation.applyCurrentRotation(rotation);
         final boolean rotateSeamlessly = mDisplayRotation.isRotatingSeamlessly();
         final Transaction transaction = getPendingTransaction();
@@ -2128,12 +2138,13 @@
     }
 
     /** @return The primary split-screen task, and {@code null} otherwise. */
-    ActivityStack getRootSplitScreenPrimaryTask() {
+    @Nullable ActivityStack getRootSplitScreenPrimaryTask() {
         return mTaskContainers.getRootSplitScreenPrimaryTask();
     }
 
-    boolean hasSplitScreenPrimaryTask() {
-        return getRootSplitScreenPrimaryTask() != null;
+    boolean isSplitScreenModeActivated() {
+        Task task = getRootSplitScreenPrimaryTask();
+        return task != null && task.hasChild();
     }
 
     ActivityStack getRootPinnedTask() {
@@ -2600,7 +2611,7 @@
         }
         amendWindowTapExcludeRegion(mTouchExcludeRegion);
         // TODO(multi-display): Support docked stacks on secondary displays.
-        if (mDisplayId == DEFAULT_DISPLAY && getRootSplitScreenPrimaryTask() != null) {
+        if (mDisplayId == DEFAULT_DISPLAY && isSplitScreenModeActivated()) {
             mDividerControllerLocked.getTouchRegion(mTmpRect);
             mTmpRegion.set(mTmpRect);
             mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -2623,8 +2634,7 @@
         // If the task is home stack and it is resizable and visible (top of its root task), we want
         // to exclude the docked stack from touch so we need the entire screen area and not just a
         // small portion which the home stack currently is resized to.
-        if (task.isActivityTypeHome() && task.isVisible() && task.getStack().getTile() != null
-                && task.isResizeable()) {
+        if (task.isActivityTypeHome() && task.isVisible() && task.isResizeable()) {
             mDisplayContent.getBounds(mTmpRect);
         } else {
             task.getDimBounds(mTmpRect);
@@ -4014,6 +4024,9 @@
         mTmpWindow = null;
         mTmpInitial = initial;
 
+        // Used to indicate that we have processed the IME window.
+        mTmpWindowsBehindIme = false;
+
         // First perform layout of any root windows (not attached to another window).
         forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
 
@@ -4328,15 +4341,8 @@
 
         @VisibleForTesting
         ActivityStack getTopStack() {
-            // TODO(task-hierarchy): Just grab index -1 once tiles are in hierarchy.
-            for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
-                final ActivityStack child = mTaskContainers.getChildAt(i);
-                if (child instanceof TaskTile) {
-                    continue;
-                }
-                return child;
-            }
-            return null;
+            final int count = mTaskContainers.getChildCount();
+            return count > 0 ? mTaskContainers.getChildAt(count - 1) : null;
         }
 
         int getIndexOf(ActivityStack stack) {
@@ -4375,10 +4381,6 @@
         }
 
         private void addStackReferenceIfNeeded(ActivityStack stack) {
-            // TODO(task-hierarchy): Remove when tiles are in hierarchy.
-            if (stack instanceof TaskTile) {
-                return;
-            }
             if (stack.isActivityTypeHome()) {
                 if (mRootHomeTask != null) {
                     if (!stack.isDescendantOf(mRootHomeTask)) {
@@ -4390,27 +4392,26 @@
                     mRootHomeTask = stack;
                 }
             }
+
+            if (!stack.isRootTask()) {
+                return;
+            }
             final int windowingMode = stack.getWindowingMode();
             if (windowingMode == WINDOWING_MODE_PINNED) {
                 if (mRootPinnedTask != null) {
-                    if (!stack.isDescendantOf(mRootPinnedTask)) {
-                        throw new IllegalArgumentException(
-                                "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
-                                        + " already exist on display=" + this + " stack=" + stack);
-                    }
-                } else {
-                    mRootPinnedTask = stack;
+                    throw new IllegalArgumentException(
+                            "addStackReferenceIfNeeded: pinned stack=" + mRootPinnedTask
+                                    + " already exist on display=" + this + " stack=" + stack);
                 }
+                mRootPinnedTask = stack;
             } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 if (mRootSplitScreenPrimaryTask != null) {
-                    if (!stack.isDescendantOf(mRootSplitScreenPrimaryTask)) {
-                        throw new IllegalArgumentException("addStackReferenceIfNeeded:"
-                                + " split-screen-primary" + " stack=" + mRootSplitScreenPrimaryTask
-                                + " already exist on display=" + this + " stack=" + stack);
-                    }
-                } else {
-                    mRootSplitScreenPrimaryTask = stack;
+                    throw new IllegalArgumentException(
+                            "addStackReferenceIfNeeded: split screen primary stack="
+                                    + mRootSplitScreenPrimaryTask
+                                    + " already exist on display=" + this + " stack=" + stack);
                 }
+                mRootSplitScreenPrimaryTask = stack;
             }
         }
 
@@ -4430,6 +4431,7 @@
             position = findPositionForStack(position, stack, true /* adding */);
 
             super.addChild(stack, position);
+            mAtmService.updateSleepIfNeededLocked();
 
             // The reparenting case is handled in WindowContainer.
             if (!stack.mReparenting) {
@@ -4441,6 +4443,7 @@
         protected void removeChild(ActivityStack stack) {
             super.removeChild(stack);
             mDisplayContent.onStackRemoved(stack);
+            mAtmService.updateSleepIfNeededLocked();
             removeStackReferenceIfNeeded(stack);
         }
 
@@ -4495,6 +4498,10 @@
          */
         private int findPositionForStack(int requestedPosition, ActivityStack stack,
                 boolean adding) {
+            if (stack.isActivityTypeDream()) {
+                return POSITION_TOP;
+            }
+
             if (stack.inPinnedWindowingMode()) {
                 return POSITION_TOP;
             }
@@ -4645,10 +4652,9 @@
                 // Apps and their containers are not allowed to specify an orientation while using
                 // root tasks...except for the home stack if it is not resizable and currently
                 // visible (top of) its root task.
-                if (mRootHomeTask != null && mRootHomeTask.isVisible()
-                        && mRootHomeTask.getTile() != null) {
+                if (mRootHomeTask != null && mRootHomeTask.isVisible()) {
                     final Task topMost = mRootHomeTask.getTopMostTask();
-                    final boolean resizable = topMost == null && topMost.isResizeable();
+                    final boolean resizable = topMost != null && topMost.isResizeable();
                     if (!(resizable && mRootHomeTask.matchParentBounds())) {
                         final int orientation = mRootHomeTask.getOrientation();
                         if (orientation != SCREEN_ORIENTATION_UNSET) {
@@ -4792,17 +4798,6 @@
                 mSplitScreenDividerAnchor = null;
             }
         }
-
-        @Override
-        void onChildPositionChanged(WindowContainer child) {
-            // TODO(task-hierarchy): Move functionality to TaskTile when it's a proper parent.
-            TaskTile tile = ((ActivityStack) child).getTile();
-            if (tile == null) {
-                return;
-            }
-            mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
-                    tile, false /* force */);
-        }
     }
 
     private class WindowContainers extends DisplayChildWindowContainer<WindowContainer> {
@@ -4983,7 +4978,7 @@
         private boolean skipImeWindowsDuringTraversal(DisplayContent dc) {
             // We skip IME windows so they're processed just above their target, except
             // in split-screen mode where we process the IME containers above the docked divider.
-            return dc.mInputMethodTarget != null && !dc.hasSplitScreenPrimaryTask();
+            return dc.mInputMethodTarget != null && !dc.isSplitScreenModeActivated();
         }
 
         /** Like {@link #forAllWindows}, but ignores {@link #skipImeWindowsDuringTraversal} */
@@ -5654,7 +5649,14 @@
     void addStack(ActivityStack stack, int position) {
         setStackOnDisplay(stack, position);
         positionStackAt(stack, position);
-        mAtmService.updateSleepIfNeededLocked();
+    }
+
+    void addStackReferenceIfNeeded(ActivityStack stack) {
+        mTaskContainers.addStackReferenceIfNeeded(stack);
+    }
+
+    void removeStackReferenceIfNeeded(ActivityStack stack) {
+        mTaskContainers.removeStackReferenceIfNeeded(stack);
     }
 
     void onStackRemoved(ActivityStack stack) {
@@ -5665,7 +5667,6 @@
             mPreferredTopFocusableStack = null;
         }
         releaseSelfIfNeeded();
-        mAtmService.updateSleepIfNeededLocked();
         onStackOrderChanged(stack);
     }
 
@@ -5703,6 +5704,14 @@
                     "positionStackAt: Can only have one task on display=" + this);
         }
 
+        final boolean movingToTop = wasContained && position >= getStackCount() - 1;
+        // Reset mPreferredTopFocusableStack before positioning to top or {@link
+        // ActivityStackSupervisor#updateTopResumedActivityIfNeeded()} won't update the top
+        // resumed activity.
+        if (movingToTop && stack.isFocusable()) {
+            mPreferredTopFocusableStack = null;
+        }
+
         // Since positionChildAt() is called during the creation process of pinned stacks,
         // ActivityStack#getStack() can be null.
         positionStackAt(position, stack, includingParents);
@@ -5712,7 +5721,7 @@
         // we are looking for top focusable stack. The condition {@code wasContained} restricts the
         // preferred stack is set only when moving an existing stack to top instead of adding a new
         // stack that may be too early (e.g. in the middle of launching or reparenting).
-        if (wasContained && position >= getStackCount() - 1 && stack.isFocusableAndVisible()) {
+        if (movingToTop && stack.isFocusableAndVisible()) {
             mPreferredTopFocusableStack = stack;
         } else if (mPreferredTopFocusableStack == stack) {
             mPreferredTopFocusableStack = null;
@@ -5755,18 +5764,54 @@
     /**
      * Returns an existing stack compatible with the windowing mode and activity type or creates one
      * if a compatible stack doesn't exist.
+     * @see #getOrCreateStack(int, int, boolean, Intent, Task, boolean)
+     */
+    ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop) {
+        return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+                null /* candidateTask */, false /* createdByOrganizer */);
+    }
+
+    /**
+     * When two level tasks are required for given windowing mode and activity type, returns an
+     * existing compatible root task or creates a new one.
+     * For one level task, the candidate task would be reused to also be the root task or create
+     * a new root task if no candidate task.
      * @see #getStack(int, int)
      * @see #createStack(int, int, boolean)
      */
-    ActivityStack getOrCreateStack(int windowingMode, int activityType,
-            boolean onTop) {
+    ActivityStack getOrCreateStack(int windowingMode, int activityType, boolean onTop,
+            Intent intent, Task candidateTask, boolean createdByOrganizer) {
         if (!alwaysCreateStack(windowingMode, activityType)) {
             ActivityStack stack = getStack(windowingMode, activityType);
             if (stack != null) {
                 return stack;
             }
+        } else if (candidateTask != null) {
+            final ActivityStack stack = (ActivityStack) candidateTask;
+            final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
+            if (isSplitScreenModeActivated()) {
+                final Task splitRootSecondary = getTask(t -> t.mCreatedByOrganizer && t.isRootTask()
+                        && t.inSplitScreenSecondaryWindowingMode());
+                if (stack.getParent() == null) {
+                    splitRootSecondary.addChild(stack, position);
+                } else if (stack.getParent() != splitRootSecondary) {
+                    stack.reparent(splitRootSecondary, position);
+                }
+            } else if (stack.getDisplay() != this || !stack.isRootTask()) {
+                if (stack.getParent() == null) {
+                    addStack(stack, position);
+                } else {
+                    stack.reparent(this, onTop);
+                }
+            }
+            // Update windowing mode if necessary, e.g. moving a pinned task to fullscreen.
+            if (candidateTask.getWindowingMode() != windowingMode) {
+                candidateTask.setWindowingMode(windowingMode);
+            }
+            return stack;
         }
-        return createStack(windowingMode, activityType, onTop);
+        return createStack(windowingMode, activityType, onTop, null /*info*/, intent,
+                createdByOrganizer);
     }
 
     /**
@@ -5784,7 +5829,8 @@
         // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
         // it's display's windowing mode.
         windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
-        return getOrCreateStack(windowingMode, activityType, onTop);
+        return getOrCreateStack(windowingMode, activityType, onTop, null /* intent */,
+                candidateTask, false /* createdByOrganizer */);
     }
 
     @VisibleForTesting
@@ -5793,7 +5839,8 @@
     }
 
     ActivityStack createStack(int windowingMode, int activityType, boolean onTop) {
-        return createStack(windowingMode, activityType, onTop, null /*info*/, null /*intent*/);
+        return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
+                false /* createdByOrganizer */);
     }
 
     /**
@@ -5805,25 +5852,29 @@
      *                     {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
      *                     be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
      * @param onTop If true the stack will be created at the top of the display, else at the bottom.
+     * @param info The started activity info.
+     * @param intent The intent that started this task.
+     * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
+     *                          otherwise.
      * @return The newly created stack.
      */
     ActivityStack createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
-            Intent intent) {
+            Intent intent, boolean createdByOrganizer) {
         if (mSingleTaskInstance && getStackCount() > 0) {
             // Create stack on default display instead since this display can only contain 1 stack.
             // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
             // this goes away once ActivityView is no longer using virtual displays.
             return mRootWindowContainer.getDefaultDisplay().createStack(
-                    windowingMode, activityType, onTop, info, intent);
+                    windowingMode, activityType, onTop, info, intent, createdByOrganizer);
         }
 
-        if (activityType == ACTIVITY_TYPE_UNDEFINED) {
+        if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
             // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
-            // anything else should be passing it in anyways...
+            // anything else should be passing it in anyways...except for the task organizer.
             activityType = ACTIVITY_TYPE_STANDARD;
         }
 
-        if (activityType != ACTIVITY_TYPE_STANDARD) {
+        if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
             // For now there can be only one stack of a particular non-standard activity type on a
             // display. So, get that ignoring whatever windowing mode it is currently in.
             ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
@@ -5842,39 +5893,39 @@
         }
 
         final int stackId = getNextStackId();
-        return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent);
+        return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
+                createdByOrganizer);
     }
 
-    /** @return the tile to create the next stack in. */
-    private TaskTile updateLaunchTile(int windowingMode) {
+    /** @return the root task to create the next task in. */
+    private Task updateLaunchRootTask(int windowingMode) {
         if (!isSplitScreenWindowingMode(windowingMode)) {
-            // Only split-screen windowing modes interact with tiles.
+            // Only split-screen windowing modes can do this currently...
             return null;
         }
         for (int i = getStackCount() - 1; i >= 0; --i) {
-            final TaskTile t = getStackAt(i).asTile();
-            if (t == null || t.getRequestedOverrideWindowingMode() != windowingMode) {
+            final Task t = getStackAt(i);
+            if (!t.mCreatedByOrganizer || t.getRequestedOverrideWindowingMode() != windowingMode) {
                 continue;
             }
-            // If not already set, pick a launch tile which is not the one we are launching
-            // into.
-            if (mLaunchTile == null) {
+            // If not already set, pick a launch root which is not the one we are launching into.
+            if (mLaunchRootTask == null) {
                 for (int j = 0, n = getStackCount(); j < n; ++j) {
-                    TaskTile tt = getStackAt(j).asTile();
-                    if (tt != t) {
-                        mLaunchTile = tt;
+                    final Task tt = getStackAt(j);
+                    if (tt.mCreatedByOrganizer && tt != t) {
+                        mLaunchRootTask = tt;
                         break;
                     }
                 }
             }
             return t;
         }
-        return mLaunchTile;
+        return mLaunchRootTask;
     }
 
     @VisibleForTesting
-    ActivityStack createStackUnchecked(int windowingMode, int activityType,
-            int stackId, boolean onTop, ActivityInfo info, Intent intent) {
+    ActivityStack createStackUnchecked(int windowingMode, int activityType, int stackId,
+            boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
         if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
             throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
                     + "activity type.");
@@ -5884,19 +5935,25 @@
             info.applicationInfo = new ApplicationInfo();
         }
 
-        TaskTile tile = updateLaunchTile(windowingMode);
-        if (tile != null) {
-            // Since this stack will be put into a tile, its windowingMode will be inherited.
+        // Task created by organizer are added as root.
+        Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
+        if (launchRootTask != null) {
+            // Since this stack will be put into a root task, its windowingMode will be inherited.
             windowingMode = WINDOWING_MODE_UNDEFINED;
         }
+
         final ActivityStack stack = (ActivityStack) Task.create(mAtmService, stackId, activityType,
-                info, intent);
-        addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
-        stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
-                false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
-                true /* creating */);
-        if (tile != null) {
-            tile.addChild(stack, 0 /* index */);
+                info, intent, createdByOrganizer);
+        if (launchRootTask != null) {
+            launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+            if (onTop) {
+                positionStackAtTop((ActivityStack) launchRootTask, false /* includingParents */);
+            }
+        } else {
+            addStack(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
+            stack.setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
+                    false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
+                    true /* creating */);
         }
         return stack;
     }
@@ -6031,7 +6088,7 @@
         mTmpFindTaskResult.clear();
         for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = getStackAt(stackNdx);
-            if (!r.hasCompatibleActivityType(stack)) {
+            if (!r.hasCompatibleActivityType(stack) && stack.isLeafTask()) {
                 if (DEBUG_TASKS) {
                     Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
                 }
@@ -6103,7 +6160,15 @@
             final int activityType = activityTypes[j];
             for (int i = getStackCount() - 1; i >= 0; --i) {
                 final ActivityStack stack = getStackAt(i);
-                if (stack.getActivityType() == activityType) {
+                // Collect the root tasks that are currently being organized.
+                if (stack.isOrganized()) {
+                    for (int k = stack.getChildCount() - 1; k >= 0; --k) {
+                        final ActivityStack childStack = (ActivityStack) stack.getChildAt(k);
+                        if (childStack.getActivityType() == activityType) {
+                            stacks.add(childStack);
+                        }
+                    }
+                } else if (stack.getActivityType() == activityType) {
                     stacks.add(stack);
                 }
             }
@@ -6117,13 +6182,8 @@
     void onSplitScreenModeDismissed() {
         mAtmService.deferWindowLayout();
         try {
-            mLaunchTile = null;
-            for (int i = getStackCount() - 1; i >= 0; --i) {
-                final TaskTile t = getStackAt(i).asTile();
-                if (t != null) {
-                    t.removeAllChildren();
-                }
-            }
+            mLaunchRootTask = null;
+            moveSplitScreenTasksToFullScreen();
         } finally {
             final ActivityStack topFullscreenStack =
                     getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -6141,6 +6201,24 @@
         }
     }
 
+    private void moveSplitScreenTasksToFullScreen() {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        mTmpTasks.clear();
+        forAllTasks(task -> {
+            if (task.mCreatedByOrganizer && task.inSplitScreenWindowingMode() && task.hasChild()) {
+                mTmpTasks.add(task);
+            }
+        });
+
+        for (int i = mTmpTasks.size() - 1; i >= 0; i--) {
+            final Task root = mTmpTasks.get(i);
+            for (int j = 0; j < root.getChildCount(); j++) {
+                wct.reparent(root.getChildAt(j).mRemoteToken, null, true /* toTop */);
+            }
+        }
+        mAtmService.mWindowOrganizerController.applyTransaction(wct);
+    }
+
     /**
      * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
      * @param windowingMode The windowing mode we are checking support for.
@@ -6253,7 +6331,7 @@
             }
         }
 
-        final boolean inSplitScreenMode = hasSplitScreenPrimaryTask();
+        final boolean inSplitScreenMode = isSplitScreenModeActivated();
         if (!inSplitScreenMode
                 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
             // Switch to the display's windowing mode if we are not in split-screen mode and we are
@@ -6278,10 +6356,6 @@
     }
 
     boolean isTopNotPinnedStack(ActivityStack stack) {
-        // TODO(task-hierarchy): Remove when tiles are in hierarchy.
-        if (stack instanceof TaskTile) {
-            return false;
-        }
         for (int i = getStackCount() - 1; i >= 0; --i) {
             final ActivityStack current = getStackAt(i);
             if (!current.inPinnedWindowingMode()) {
@@ -6418,15 +6492,20 @@
 
     @Override
     public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        final int currRotation =
-                getRequestedOverrideConfiguration().windowConfiguration.getRotation();
-        if (currRotation != ROTATION_UNDEFINED
-                && currRotation != overrideConfiguration.windowConfiguration.getRotation()) {
-            applyRotationLocked(currRotation,
-                    overrideConfiguration.windowConfiguration.getRotation());
+        final Configuration currOverrideConfig = getRequestedOverrideConfiguration();
+        final int currRotation = currOverrideConfig.windowConfiguration.getRotation();
+        final int overrideRotation = overrideConfiguration.windowConfiguration.getRotation();
+        if (currRotation != ROTATION_UNDEFINED && currRotation != overrideRotation) {
+            if (mFixedRotationLaunchingApp != null) {
+                mFixedRotationLaunchingApp.clearFixedRotationTransform(
+                        () -> applyRotation(currRotation, overrideRotation));
+                // Clear the record because the display will sync to current rotation.
+                mFixedRotationLaunchingApp = null;
+            } else {
+                applyRotation(currRotation, overrideRotation);
+            }
         }
-        mCurrentOverrideConfigurationChanges =
-            getRequestedOverrideConfiguration().diff(overrideConfiguration);
+        mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
         super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
         mCurrentOverrideConfigurationChanges = 0;
         mWmService.setNewDisplayOverrideConfiguration(overrideConfiguration, this);
@@ -6503,7 +6582,7 @@
                     // If default display is in split-window mode, set windowing mode of the stack
                     // to split-screen secondary. Otherwise, set the windowing mode to undefined by
                     // default to let stack inherited the windowing mode from the new display.
-                    final int windowingMode = toDisplay.hasSplitScreenPrimaryTask()
+                    final int windowingMode = toDisplay.isSplitScreenModeActivated()
                             ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                             : WINDOWING_MODE_UNDEFINED;
                     stack.reparent(toDisplay, true /* onTop */);
@@ -6607,27 +6686,35 @@
      *         already top-most.
      */
     ActivityStack getStackAbove(ActivityStack stack) {
-        final int stackIndex = getIndexOf(stack) + 1;
-        return (stackIndex < getStackCount()) ? getStackAt(stackIndex) : null;
+        final WindowContainer wc = stack.getParent();
+        final int index = wc.mChildren.indexOf(stack) + 1;
+        return (index < wc.mChildren.size()) ? (ActivityStack) wc.mChildren.get(index) : null;
     }
 
     /**
      * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
      * Generally used in conjunction with {@link #moveStackBehindStack}.
      */
+    // TODO(b/151575894): Remove special stack movement methods.
     void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
         if (stack.shouldBeVisible(null)) {
             // Skip if the stack is already visible
             return;
         }
 
-        // Move the stack to the bottom to not affect the following visibility checks
-        positionStackAtBottom(stack);
+        final boolean isRootTask = stack.isRootTask();
+        if (isRootTask) {
+            // Move the stack to the bottom to not affect the following visibility checks
+            positionStackAtBottom(stack);
+        } else {
+            stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
+        }
 
         // Find the next position where the stack should be placed
-        final int numStacks = getStackCount();
+        final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
         for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
-            final ActivityStack s = getStackAt(stackNdx);
+            final ActivityStack s = isRootTask ? getStackAt(stackNdx)
+                    : (ActivityStack) stack.getParent().getChildAt(stackNdx);
             if (s == stack) {
                 continue;
             }
@@ -6636,7 +6723,12 @@
                     || winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
             if (s.shouldBeVisible(null) && isValidWindowingMode) {
                 // Move the provided stack to behind this stack
-                positionStackAt(stack, Math.max(0, stackNdx - 1));
+                final int position = Math.max(0, stackNdx - 1);
+                if (isRootTask) {
+                    positionStackAt(stack, position);
+                } else {
+                    stack.getParent().positionChildAt(position, stack, false /*includingParents */);
+                }
                 break;
             }
         }
@@ -6652,15 +6744,25 @@
             return;
         }
 
+        final WindowContainer parent = stack.getParent();
+        if (parent == null || parent != behindStack.getParent()) {
+            return;
+        }
+
         // Note that positionChildAt will first remove the given stack before inserting into the
         // list, so we need to adjust the insertion index to account for the removed index
         // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
         //       position internally
-        final int stackIndex = getIndexOf(stack);
-        final int behindStackIndex = getIndexOf(behindStack);
+        final int stackIndex = parent.mChildren.indexOf(stack);
+        final int behindStackIndex = parent.mChildren.indexOf(behindStack);
         final int insertIndex = stackIndex <= behindStackIndex
                 ? behindStackIndex - 1 : behindStackIndex;
-        positionStackAt(stack, Math.max(0, insertIndex));
+        final int position = Math.max(0, insertIndex);
+        if (stack.isRootTask()) {
+            positionStackAt(stack, position);
+        } else {
+            parent.positionChildAt(position, stack, false /* includingParents */);
+        }
     }
 
     void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
@@ -6697,19 +6799,6 @@
         return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
     }
 
-    // TODO(task-hierarchy): Remove when tiles are in hierarchy.
-    void addTile(TaskTile tile) {
-        mTaskContainers.addChild(tile, POSITION_BOTTOM);
-        ITaskOrganizer organizer = mAtmService.mTaskOrganizerController.getTaskOrganizer(
-                tile.getWindowingMode());
-        tile.setTaskOrganizer(organizer);
-    }
-
-    // TODO(task-hierarchy): Remove when tiles are in hierarchy.
-    void removeTile(TaskTile tile) {
-        mTaskContainers.removeChild(tile);
-    }
-
     @Nullable
     ActivityRecord getHomeActivityForUser(int userId) {
         final ActivityStack homeStack = getRootHomeTask();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5e88fb0..f593393 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -29,7 +29,6 @@
 import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
 import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
-import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
 import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -1493,14 +1492,8 @@
      */
     public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
         displayFrames.onBeginLayout();
-        final InsetsState insetsState =
-                mDisplayContent.getInsetsStateController().getRawInsetsState();
-
-        // Reset the frame of IME so that the layout of windows above IME won't get influenced.
-        // Once we layout the IME, frames will be set again on the source.
-        insetsState.getSource(ITYPE_IME).setFrame(0, 0, 0, 0);
-
-        updateInsetsStateForDisplayCutout(displayFrames, insetsState);
+        updateInsetsStateForDisplayCutout(displayFrames,
+                mDisplayContent.getInsetsStateController().getRawInsetsState());
         mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
         mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
 
@@ -1527,25 +1520,7 @@
                 && (mNotificationShade.getAttrs().privateFlags
                 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
 
-        // When the navigation bar isn't visible, we put up a fake input window to catch all
-        // touch events. This way we can detect when the user presses anywhere to bring back the
-        // nav bar and ensure the application doesn't see the event.
-        if (navVisible || navAllowedHidden) {
-            if (mInputConsumer != null) {
-                mInputConsumer.dismiss();
-                mHandler.sendMessage(
-                        mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
-                mInputConsumer = null;
-            }
-        } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
-            mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
-                    mHandler.getLooper(),
-                    INPUT_CONSUMER_NAVIGATION,
-                    HideNavInputEventReceiver::new);
-            // As long as mInputConsumer is active, hover events are not dispatched to the app
-            // and the pointer icon is likely to become stale. Hide it to avoid confusion.
-            InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
-        }
+        updateHideNavInputEventReceiver(navVisible, navAllowedHidden);
 
         // For purposes of positioning and showing the nav bar, if we have decided that it can't
         // be hidden (because of the screen aspect ratio), then take that into account.
@@ -1567,6 +1542,28 @@
         mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
     }
 
+    void updateHideNavInputEventReceiver(boolean navVisible, boolean navAllowedHidden) {
+        // When the navigation bar isn't visible, we put up a fake input window to catch all
+        // touch events. This way we can detect when the user presses anywhere to bring back the
+        // nav bar and ensure the application doesn't see the event.
+        if (navVisible || navAllowedHidden) {
+            if (mInputConsumer != null) {
+                mInputConsumer.dismiss();
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
+                mInputConsumer = null;
+            }
+        } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
+            mInputConsumer = mDisplayContent.getInputMonitor().createInputConsumer(
+                    mHandler.getLooper(),
+                    INPUT_CONSUMER_NAVIGATION,
+                    HideNavInputEventReceiver::new);
+            // As long as mInputConsumer is active, hover events are not dispatched to the app
+            // and the pointer icon is likely to become stale. Hide it to avoid confusion.
+            InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
+        }
+    }
+
     private static void updateInsetsStateForDisplayCutout(DisplayFrames displayFrames,
             InsetsState state) {
         if (displayFrames.mDisplayCutout.getDisplayCutout().isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 60b817c..af89a05 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -484,11 +484,8 @@
             prepareNormalRotationAnimation();
         }
 
-        // TODO(b/147469351): Remove the restriction.
-        if (mDisplayContent.mFixedRotationLaunchingApp == null) {
-            // Give a remote handler (system ui) some time to reposition things.
-            startRemoteRotation(oldRotation, mRotation);
-        }
+        // Give a remote handler (system ui) some time to reposition things.
+        startRemoteRotation(oldRotation, mRotation);
 
         return true;
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 88cdd17..18332b9 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -62,7 +62,7 @@
     // When true, need to call updateInputWindowsLw().
     private boolean mUpdateInputWindowsNeeded = true;
     private boolean mUpdateInputWindowsPending;
-    private boolean mApplyImmediately;
+    private boolean mUpdateInputWindowsImmediately;
 
     // Currently focused input window handle.
     private InputWindowHandle mFocusedInputWindowHandle;
@@ -347,14 +347,20 @@
         }
     }
 
-    void updateInputWindowsImmediately() {
+    /**
+     * Immediately update the input transaction and merge into the passing Transaction that could be
+     * collected and applied later.
+     */
+    void updateInputWindowsImmediately(SurfaceControl.Transaction t) {
         mHandler.removeCallbacks(mUpdateInputWindows);
-        mApplyImmediately = true;
+        mUpdateInputWindowsImmediately = true;
         mUpdateInputWindows.run();
-        mApplyImmediately = false;
+        mUpdateInputWindowsImmediately = false;
+        t.merge(mInputTransaction);
     }
 
-    /* Called when the current input focus changes.
+    /**
+     * Called when the current input focus changes.
      * Layer assignment is assumed to be complete by the time this is called.
      */
     public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
@@ -465,10 +471,7 @@
             if (mAddWallpaperInputConsumerHandle) {
                 mWallpaperInputConsumer.show(mInputTransaction, 0);
             }
-
-            if (mApplyImmediately) {
-                mInputTransaction.apply();
-            } else {
+            if (!mUpdateInputWindowsImmediately) {
                 mDisplayContent.getPendingTransaction().merge(mInputTransaction);
                 mDisplayContent.scheduleAnimation();
             }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index bb02789..fda70d1 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -25,6 +25,7 @@
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
 
@@ -91,6 +92,13 @@
                 || focusedWin != getNavControlTarget(focusedWin)
                 || focusedWin.getRequestedInsetsState().getSource(ITYPE_NAVIGATION_BAR)
                         .isVisible());
+        updateHideNavInputEventReceiver();
+    }
+
+    private void updateHideNavInputEventReceiver() {
+        mPolicy.updateHideNavInputEventReceiver(!isHidden(ITYPE_NAVIGATION_BAR),
+                mFocusedWin != null
+                        && mFocusedWin.mAttrs.insetsFlags.behavior != BEHAVIOR_SHOW_BARS_BY_TOUCH);
     }
 
     boolean isHidden(@InternalInsetsType int type) {
@@ -169,6 +177,7 @@
         if (windowState == getNavControlTarget(mFocusedWin)) {
             mNavBar.setVisible(state.getSource(ITYPE_NAVIGATION_BAR).isVisible());
         }
+        updateHideNavInputEventReceiver();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index a4bdfb3..04454a5 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -88,8 +88,8 @@
         final InsetsSourceProvider provider = target.getControllableInsetProvider();
         final @InternalInsetsType int type = provider != null
                 ? provider.getSource().getType() : ITYPE_INVALID;
-        return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
-                target.isAlwaysOnTop());
+        return getInsetsForDispatchInner(type, target.getWindowingMode(), target.isAlwaysOnTop(),
+                isAboveIme(target));
     }
 
     InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
@@ -97,13 +97,24 @@
         final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
         final @WindowingMode int windowingMode = token != null
                 ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
-        final boolean alwaysOnTop = token != null
-                ? token.isAlwaysOnTop() : false;
-        return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
+        final boolean alwaysOnTop = token != null && token.isAlwaysOnTop();
+        return getInsetsForDispatchInner(type, windowingMode, alwaysOnTop, isAboveIme(token));
+    }
+
+    private boolean isAboveIme(WindowContainer target) {
+        final WindowState imeWindow = mDisplayContent.mInputMethodWindow;
+        if (target == null || imeWindow == null) {
+            return false;
+        }
+        if (target instanceof WindowState) {
+            final WindowState win = (WindowState) target;
+            return win.needsRelativeLayeringToIme() || !win.mBehindIme;
+        }
+        return false;
     }
 
     private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
-        switch(type) {
+        switch (type) {
             case TYPE_STATUS_BAR:
                 return ITYPE_STATUS_BAR;
             case TYPE_NAVIGATION_BAR:
@@ -116,8 +127,8 @@
     }
 
     /** @see #getInsetsForDispatch */
-    private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
-            @WindowingMode int windowingMode, boolean isAlwaysOnTop) {
+    private InsetsState getInsetsForDispatchInner(@InternalInsetsType int type,
+            @WindowingMode int windowingMode, boolean isAlwaysOnTop, boolean aboveIme) {
         InsetsState state = mState;
 
         if (type != ITYPE_INVALID) {
@@ -158,6 +169,11 @@
             state.removeSource(ITYPE_NAVIGATION_BAR);
         }
 
+        if (aboveIme) {
+            state = new InsetsState(state);
+            state.removeSource(ITYPE_IME);
+        }
+
         return state;
     }
 
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 44034ed..6b39fd2 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -406,12 +406,11 @@
             // show on top of the lock screen. In this can we want to dismiss the docked
             // stack since it will be complicated/risky to try to put the activity on top
             // of the lock screen in the right fullscreen configuration.
-            final ActivityStack stack =
-                    mRootWindowContainer.getDefaultDisplay().getRootSplitScreenPrimaryTask();
-            if (stack == null) {
+            final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+            if (!display.isSplitScreenModeActivated()) {
                 return;
             }
-            mRootWindowContainer.getDefaultDisplay().onSplitScreenModeDismissed();
+            display.onSplitScreenModeDismissed();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index bd5666d..12be9df 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -21,9 +21,11 @@
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -1298,6 +1300,7 @@
         switch (task.getActivityType()) {
             case ACTIVITY_TYPE_HOME:
             case ACTIVITY_TYPE_RECENTS:
+            case ACTIVITY_TYPE_DREAM:
                 // Ignore certain activity types completely
                 return false;
             case ACTIVITY_TYPE_ASSISTANT:
@@ -1307,6 +1310,7 @@
                         == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) {
                     return false;
                 }
+                break;
         }
 
         // Ignore certain windowing modes
@@ -1314,23 +1318,21 @@
             case WINDOWING_MODE_PINNED:
                 return false;
             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
-                if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask());
+                if (DEBUG_RECENTS_TRIM_TASKS) {
+                    Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask());
+                }
                 final ActivityStack stack = task.getStack();
                 if (stack != null && stack.getTopMostTask() == task) {
                     // Only the non-top task of the primary split screen mode is visible
                     return false;
                 }
-        }
-
-        // Tasks managed by/associated with an ActivityView should be excluded from recents.
-        // singleTaskInstance is set on the VirtualDisplay managed by ActivityView
-        // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance
-        final ActivityStack stack = task.getStack();
-        if (stack != null) {
-            DisplayContent display = stack.getDisplay();
-            if (display != null && display.isSingleTaskInstance()) {
-                return false;
-            }
+                break;
+            case WINDOWING_MODE_MULTI_WINDOW:
+                // Ignore tasks that are always on top
+                if (task.isAlwaysOnTop()) {
+                    return false;
+                }
+                break;
         }
 
         // If we're in lock task mode, ignore the root task
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index adafdec..9089240 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -388,11 +388,12 @@
                     // surfaces needs to be done immediately.
                     mWindowManager.executeAppTransition();
 
-                    if (targetStack.getTile() != null) {
+                    final Task rootTask = targetStack.getRootTask();
+                    if (rootTask.isOrganized()) {
                         // Client state may have changed during the recents animation, so force
                         // send task info so the client can synchronize its state.
                         mService.mTaskOrganizerController.dispatchTaskInfoChanged(
-                                targetStack.mTile, true /* force */);
+                                rootTask, true /* force */);
                     }
                 } catch (Exception e) {
                     Slog.e(TAG, "Failed to clean up recents activity", e);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3e5cb50..a30b70d 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -667,7 +667,7 @@
                         mTargetActivityRecord.token);
             }
             if (mTargetActivityRecord.hasFixedRotationTransform()) {
-                mTargetActivityRecord.clearFixedRotationTransform();
+                mTargetActivityRecord.finishFixedRotationTransform();
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
index 45f8a15..420997a 100644
--- a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
+++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java
@@ -20,7 +20,6 @@
 import static com.android.server.wm.ActivityStack.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
 
 import android.app.ActivityOptions;
 import android.content.Intent;
@@ -233,29 +232,6 @@
         }
 
         final ActivityTaskManagerService atmService = mTargetStack.mAtmService;
-        final ArrayList<Task> createdTasks = new ArrayList<>();
-        while (!mPendingReparentActivities.isEmpty()) {
-            final ActivityRecord r = mPendingReparentActivities.remove(0);
-            final ActivityRecord bottom = mTargetStack.getBottomMostActivity();
-            final Task targetTask;
-            if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) {
-                // If the activity currently at the bottom has the same task affinity as
-                // the one we are moving, then merge it into the same task.
-                targetTask = bottom.getTask();
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
-                        + r + " out to bottom task " + targetTask);
-            } else {
-                targetTask = mTargetStack.reuseOrCreateTask(
-                        r.info, null /*intent*/, false /*toTop*/);
-                targetTask.affinityIntent = r.intent;
-                createdTasks.add(targetTask);
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
-                        + r + " out to new task " + targetTask);
-            }
-            r.reparent(targetTask, 0 /* position */, "resetTargetTaskIfNeeded");
-            atmService.mStackSupervisor.mRecentTasks.add(targetTask);
-        }
-
         DisplayContent display = mTargetStack.getDisplay();
         final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance();
         if (singleTaskInstanceDisplay) {
@@ -264,16 +240,33 @@
 
         final int windowingMode = mTargetStack.getWindowingMode();
         final int activityType = mTargetStack.getActivityType();
-        if (!singleTaskInstanceDisplay && !display.alwaysCreateStack(windowingMode, activityType)) {
-            return;
-        }
 
-        while (!createdTasks.isEmpty()) {
-            final Task targetTask = createdTasks.remove(createdTasks.size() - 1);
-            final ActivityStack targetStack = display.getOrCreateStack(
-                    windowingMode, activityType, false /* onTop */);
-            targetTask.reparent(targetStack, false /* toTop */, REPARENT_LEAVE_STACK_IN_PLACE,
-                    false /* animate */, true /* deferResume */, "resetTargetTask");
+        while (!mPendingReparentActivities.isEmpty()) {
+            final ActivityRecord r = mPendingReparentActivities.remove(0);
+            final boolean alwaysCreateTask = DisplayContent.alwaysCreateStack(windowingMode,
+                    activityType);
+            final Task task = alwaysCreateTask
+                    ? display.getBottomMostTask() : mTargetStack.getBottomMostTask();
+            Task targetTask = null;
+            if (task != null && r.taskAffinity.equals(task.affinity)) {
+                // If the activity currently at the bottom has the same task affinity as
+                // the one we are moving, then merge it into the same task.
+                targetTask = task;
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity "
+                        + r + " out to bottom task " + targetTask);
+            }
+            if (targetTask == null) {
+                if (alwaysCreateTask) {
+                    targetTask = display.getOrCreateStack(windowingMode, activityType,
+                            false /* onTop */);
+                } else {
+                    targetTask = mTargetStack.reuseOrCreateTask(r.info, null /*intent*/,
+                            false /*toTop*/);
+                }
+                targetTask.affinityIntent = r.intent;
+            }
+            r.reparent(targetTask, 0 /* position */, "resetTargetTaskIfNeeded");
+            atmService.mStackSupervisor.mRecentTasks.add(targetTask);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ebf1bc9..6eb988b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
@@ -1970,8 +1971,7 @@
         final int focusStackId = topFocusedStack != null
                 ? topFocusedStack.getRootTaskId() : INVALID_TASK_ID;
         // We dismiss the docked stack whenever we switch users.
-        final ActivityStack dockedStack = getDefaultDisplay().getRootSplitScreenPrimaryTask();
-        if (dockedStack != null) {
+        if (getDefaultDisplay().isSplitScreenModeActivated()) {
             getDefaultDisplay().onSplitScreenModeDismissed();
         }
         // Also dismiss the pinned stack whenever we switch users. Removing the pinned stack will
@@ -2110,20 +2110,18 @@
             final ActivityStack stack;
             if (singleActivity) {
                 stack = r.getRootTask();
+                stack.setWindowingMode(WINDOWING_MODE_PINNED);
             } else {
-                // In the case of multiple activities, we will create a new stack for it and then
-                // move the PIP activity into the stack.
-                // We will then perform a windowing mode change for both scenarios.
-                stack = display.createStack(
-                        r.getRootTask().getRequestedOverrideWindowingMode(),
-                        r.getActivityType(), ON_TOP, r.info, r.intent);
+                // In the case of multiple activities, we will create a new task for it and then
+                // move the PIP activity into the task.
+                stack = display.createStack(WINDOWING_MODE_PINNED, r.getActivityType(), ON_TOP,
+                        r.info, r.intent, false /* createdByOrganizer */);
+
                 // There are multiple activities in the task and moving the top activity should
                 // reveal/leave the other activities in their original task.
                 r.reparent(stack, MAX_VALUE, "moveActivityToStack");
             }
 
-            stack.setWindowingMode(WINDOWING_MODE_PINNED);
-
             // Reset the state that indicates it can enter PiP while pausing after we've moved it
             // to the pinned stack
             r.supportsEnterPipOnTaskSwitch = false;
@@ -2799,16 +2797,19 @@
         if (stack == null && r != null) {
             stack = r.getRootTask();
         }
+        int windowingMode = launchParams != null ? launchParams.mWindowingMode
+                : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
         if (stack != null) {
             display = stack.getDisplay();
             if (display != null && canLaunchOnDisplay(r, display.mDisplayId)) {
-                int windowingMode = launchParams != null ? launchParams.mWindowingMode
-                        : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
                 if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
                     windowingMode = display.resolveWindowingMode(r, options, candidateTask,
                             activityType);
                 }
-                if (stack.isCompatible(windowingMode, activityType)) {
+                // Always allow organized tasks that created by organizer since the activity type
+                // of an organized task is decided by the activity type of its top child, which
+                // could be incompatible with the given windowing mode and activity type.
+                if (stack.isCompatible(windowingMode, activityType) || stack.mCreatedByOrganizer) {
                     return stack;
                 }
                 if (windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY
@@ -2826,6 +2827,10 @@
 
         if (display == null || !canLaunchOnDisplay(r, display.mDisplayId)) {
             display = getDefaultDisplay();
+            if (windowingMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED) {
+                windowingMode = display.resolveWindowingMode(r, options, candidateTask,
+                        activityType);
+            }
         }
 
         return display.getOrCreateStack(r, options, candidateTask, activityType, onTop);
@@ -2847,7 +2852,8 @@
      * @param candidateTask The possible task the activity might be put in.
      * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
      */
-    private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
+    @VisibleForTesting
+    ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
             @Nullable Task candidateTask, @Nullable ActivityOptions options,
             @Nullable LaunchParamsController.LaunchParams launchParams) {
         final DisplayContent displayContent = getDisplayContentOrCreate(displayId);
@@ -2868,6 +2874,13 @@
             if (attachedDisplayId == INVALID_DISPLAY || attachedDisplayId == displayId) {
                 return candidateTask.getStack();
             }
+            // Or the candidate task is already a root task that can be reused by reparenting
+            // it to the target display.
+            if (candidateTask.isRootTask()) {
+                final ActivityStack stack = candidateTask.getStack();
+                displayContent.moveStackToDisplay(stack, true /* onTop */);
+                return stack;
+            }
         }
 
         int windowingMode;
@@ -2915,11 +2928,10 @@
             case ACTIVITY_TYPE_HOME: return r.isActivityTypeHome();
             case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
             case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
+            case ACTIVITY_TYPE_DREAM: return r.isActivityTypeDream();
         }
-        // TODO(task-hierarchy): Find another way to differentiate tile from normal stack once it is
-        //                       part of the hierarchy
-        if (stack instanceof TaskTile) {
-            // Don't launch directly into tiles.
+        if (stack.mCreatedByOrganizer) {
+            // Don't launch directly into task created by organizer...but why can't we?
             return false;
         }
         // There is a 1-to-1 relationship between stack and task when not in
@@ -3381,11 +3393,10 @@
 
     @VisibleForTesting
     void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list,
-            @WindowConfiguration.ActivityType int ignoreActivityType,
-            @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid,
-            boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
-        mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType,
-                ignoreWindowingMode, this, callingUid, allowed, crossUser, profileIds);
+            boolean filterOnlyVisibleRecents, int callingUid, boolean allowed, boolean crossUser,
+            ArraySet<Integer> profileIds) {
+        mStackSupervisor.getRunningTasks().getTasks(maxNum, list, filterOnlyVisibleRecents, this,
+                callingUid, allowed, crossUser, profileIds);
     }
 
     void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) {
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 02077fb..3509ba72 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -16,12 +16,10 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 
 import android.app.ActivityManager.RunningTaskInfo;
-import android.app.WindowConfiguration.ActivityType;
-import android.app.WindowConfiguration.WindowingMode;
 import android.os.UserHandle;
 import android.util.ArraySet;
 
@@ -49,13 +47,13 @@
     private boolean mCrossUser;
     private ArraySet<Integer> mProfileIds;
     private boolean mAllowed;
-    private int mIgnoreActivityType;
-    private int mIgnoreWindowingMode;
+    private boolean mFilterOnlyVisibleRecents;
     private ActivityStack mTopDisplayFocusStack;
+    private RecentTasks mRecentTasks;
 
-    void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
-            @WindowingMode int ignoreWindowingMode, RootWindowContainer root,
-            int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
+    void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents,
+            RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser,
+            ArraySet<Integer> profileIds) {
         // Return early if there are no tasks to fetch
         if (maxNum <= 0) {
             return;
@@ -68,9 +66,9 @@
         mCrossUser = crossUser;
         mProfileIds = profileIds;
         mAllowed = allowed;
-        mIgnoreActivityType = ignoreActivityType;
-        mIgnoreWindowingMode = ignoreWindowingMode;
+        mFilterOnlyVisibleRecents = filterOnlyVisibleRecents;
         mTopDisplayFocusStack = root.getTopDisplayFocusedStack();
+        mRecentTasks = root.mService.getRecentTasks();
 
         final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
                 PooledLambda.__(Task.class));
@@ -107,14 +105,12 @@
                 return;
             }
         }
-        if (mIgnoreActivityType != ACTIVITY_TYPE_UNDEFINED
-                && task.getActivityType() == mIgnoreActivityType) {
-            // Skip ignored activity type
-            return;
-        }
-        if (mIgnoreWindowingMode != WINDOWING_MODE_UNDEFINED
-                && task.getWindowingMode() == mIgnoreWindowingMode) {
-            // Skip ignored windowing mode
+        if (mFilterOnlyVisibleRecents
+                && task.getActivityType() != ACTIVITY_TYPE_HOME
+                && task.getActivityType() != ACTIVITY_TYPE_RECENTS
+                && !mRecentTasks.isVisibleRecentTask(task)) {
+            // Skip if this task wouldn't be visibile (ever) from recents, with an exception for the
+            // home & recent tasks
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index cd4fb3d..7a41ea5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -20,6 +20,9 @@
 import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
@@ -114,7 +117,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Debug;
 import android.os.IBinder;
@@ -489,6 +491,17 @@
     PictureInPictureParams mPictureInPictureParams = new PictureInPictureParams.Builder().build();
 
     /**
+     * This task was created by the task organizer which has the following implementations.
+     * <ul>
+     *     <lis>The task won't be removed when it is empty. Removal has to be an explicit request
+     *     from the task organizer.</li>
+     *     <li>Unlike other non-root tasks, it's direct children are visible to the task
+     *     organizer for ordering purposes.</li>
+     * </ul>
+     */
+    boolean mCreatedByOrganizer;
+
+    /**
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
      */
@@ -1353,7 +1366,7 @@
         if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
             return applicationType;
         }
-        return getChildAt(0).getActivityType();
+        return getTopChild().getActivityType();
     }
 
     @Override
@@ -1366,6 +1379,12 @@
 
         ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
 
+        // A rootable task that is now being added to be the child of an organized task. Making
+        // sure the stack references is keep updated.
+        if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
+            mDisplayContent.addStackReferenceIfNeeded((ActivityStack) child);
+        }
+
         // Make sure the list of display UID whitelists is updated
         // now that this record is in a new task.
         mRootWindowContainer.updateUIDsPresentOnDisplay();
@@ -1406,6 +1425,11 @@
 
     @Override
     void removeChild(WindowContainer child) {
+        // A rootable child task that is now being removed from an organized task. Making sure
+        // the stack references is keep updated.
+        if (mTaskOrganizer != null && mCreatedByOrganizer && child.asTask() != null) {
+            mDisplayContent.removeStackReferenceIfNeeded((ActivityStack) child);
+        }
         removeChild(child, "removeChild");
     }
 
@@ -1453,8 +1477,9 @@
                 mStackSupervisor.removeTask(this, false /* killProcess */,
                         !REMOVE_FROM_RECENTS, reason);
             }
-        } else if (!mReuseTask) {
+        } else if (!mReuseTask && !mCreatedByOrganizer) {
             // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
+            // or created by task organizer.
             if (!isRootTask) {
                 getStack().removeChild(this, reason);
             }
@@ -1866,7 +1891,12 @@
         final Task parentTask = getParent().asTask();
         if (parentTask != null) {
             parentTask.onActivityStateChanged(record, state, reason);
-            return;
+            // We still want to update the resumed activity if the parent task is created by
+            // organizer in order to keep the information synced once got reparented out from the
+            // organized task.
+            if (!parentTask.mCreatedByOrganizer) {
+                return;
+            }
         }
 
         if (record == mResumedActivity && state != RESUMED) {
@@ -2300,18 +2330,30 @@
         return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize);
     }
 
-    void resolveTileOverrideConfiguration(Configuration newParentConfig) {
+    private void resolveOrganizedOverrideConfiguration(Configuration newParentConfig) {
         super.resolveOverrideConfiguration(newParentConfig);
+        if (!isOrganized()) {
+            return;
+        }
+
+        final Task root = getRootTask();
+        if (root == this) {
+            return;
+        }
+
+        // Ensure to have the same windowing mode for the child tasks that controlled by task org.
+        getResolvedOverrideConfiguration().windowConfiguration
+                .setWindowingMode(root.getWindowingMode());
     }
 
     @Override
     void resolveOverrideConfiguration(Configuration newParentConfig) {
-        if (!isLeafTask()) {
-            resolveTileOverrideConfiguration(newParentConfig);
+        if (!isLeafTask() || mCreatedByOrganizer) {
+            resolveOrganizedOverrideConfiguration(newParentConfig);
             return;
         }
         mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
-        resolveTileOverrideConfiguration(newParentConfig);
+        resolveOrganizedOverrideConfiguration(newParentConfig);
         int windowingMode =
                 getResolvedOverrideConfiguration().windowConfiguration.getWindowingMode();
         if (windowingMode == WINDOWING_MODE_UNDEFINED) {
@@ -2400,7 +2442,9 @@
     }
 
     Rect updateOverrideConfigurationFromLaunchBounds() {
-        final Rect bounds = getLaunchBounds();
+        // If the task is controlled by another organized task, do not set override
+        // configurations and let its parent (organized task) to control it;
+        final Rect bounds = isOrganized() && !isRootTask() ? null : getLaunchBounds();
         setBounds(bounds);
         if (bounds != null && !bounds.isEmpty()) {
             // TODO: Review if we actually want to do this - we are setting the launch bounds
@@ -2584,7 +2628,7 @@
         // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
         if (suggestedPosition == POSITION_BOTTOM && minPosition == 0) {
             return POSITION_BOTTOM;
-        } else if (suggestedPosition == POSITION_TOP && maxPosition == (size - 1)) {
+        } else if (suggestedPosition == POSITION_TOP && maxPosition >= (size - 1)) {
             return POSITION_TOP;
         }
         // Reset position based on minimum/maximum possible positions.
@@ -3203,6 +3247,20 @@
     }
 
     @Override
+    int getOrientation(int candidate) {
+        return canSpecifyOrientation() ? super.getOrientation(candidate) : SCREEN_ORIENTATION_UNSET;
+    }
+
+    private boolean canSpecifyOrientation() {
+        final int windowingMode = getWindowingMode();
+        final int activityType = getActivityType();
+        return windowingMode == WINDOWING_MODE_FULLSCREEN
+                || activityType == ACTIVITY_TYPE_HOME
+                || activityType == ACTIVITY_TYPE_RECENTS
+                || activityType == ACTIVITY_TYPE_ASSISTANT;
+    }
+
+    @Override
     boolean fillsParent() {
         return matchParentBounds();
     }
@@ -3368,14 +3426,12 @@
         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
         info.configuration.setTo(getConfiguration());
         info.token = mRemoteToken;
-        // Get's the first non-undefined activity type among this and children. Can't use
-        // configuration.windowConfiguration because that would only be this level.
-        info.topActivityType = getActivityType();
 
         //TODO (AM refactor): Just use local once updateEffectiveIntent is run during all child
         //                    order changes.
         final Task top = getTopMostTask();
         info.resizeMode = top != null ? top.mResizeMode : mResizeMode;
+        info.topActivityType = top.getActivityType();
 
         if (mPictureInPictureParams.empty()) {
             info.pictureInPictureParams = null;
@@ -3406,10 +3462,6 @@
         return this;
     }
 
-    TaskTile asTile() {
-        return null;
-    }
-
     // TODO(task-merge): Figure-out how this should work with hierarchy tasks.
     boolean shouldBeVisible(ActivityRecord starting) {
         return true;
@@ -3705,8 +3757,9 @@
     }
 
     static Task create(ActivityTaskManagerService service, int taskId, int activityType,
-            ActivityInfo info, Intent intent) {
-        return getTaskFactory().create(service, taskId, activityType, info, intent);
+            ActivityInfo info, Intent intent, boolean createdByOrganizer) {
+        return getTaskFactory().create(service, taskId, activityType, info, intent,
+                createdByOrganizer);
     }
 
     static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
@@ -3728,8 +3781,9 @@
      */
     static class TaskFactory {
         Task create(ActivityTaskManagerService service, int taskId, int activityType,
-                ActivityInfo info, Intent intent) {
-            return new ActivityStack(service, taskId, activityType, info, intent);
+                ActivityInfo info, Intent intent, boolean createdByOrganizer) {
+            return new ActivityStack(service, taskId, activityType, info, intent,
+                    createdByOrganizer);
         }
 
         Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
@@ -4005,21 +4059,29 @@
     @Override
     boolean isOrganized() {
         final Task rootTask = getRootTask();
-        // if the rootTask is a "child" of a tile, then don't consider it a root task.
-        // TODO: remove this along with removing tile.
-        if (((ActivityStack) rootTask).getTile() != null) {
+        if (rootTask.mTaskOrganizer == null) {
+            // You are obviously not organized...
             return false;
         }
-        return rootTask == this && rootTask.mTaskOrganizer != null;
+        if (rootTask == this) {
+            // Root tasks can be organized.
+            return true;
+        }
+        if (rootTask.mCreatedByOrganizer && getParent() == rootTask) {
+            // Direct children of tasks added by the organizer can the organized.
+            return true;
+        }
+
+        return false;
     }
 
     @Override
     protected void reparentSurfaceControl(SurfaceControl.Transaction t, SurfaceControl newParent) {
         /**
-         * Avoid yanking back control from the TaskOrganizer, which has presumably reparented the
-         * Surface in to its own hierarchy.
+         * Avoid reparenting SurfaceControl of the organized tasks that are always on top, since
+         * the surfaces should be controlled by the organizer itself, like bubbles.
          */
-        if (isOrganized()) {
+        if (isOrganized() && isAlwaysOnTop()) {
             return;
         }
         super.reparentSurfaceControl(t, newParent);
@@ -4049,11 +4111,13 @@
         return true;
     }
 
-    // Called on Binder death.
-    void taskOrganizerDied() {
+    void taskOrganizerUnregistered() {
         mTaskOrganizer = null;
         mLastTaskOrganizerWindowingMode = -1;
         onTaskOrganizerChanged();
+        if (mCreatedByOrganizer) {
+            removeImmediately();
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 5523678..4382e9d 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
@@ -27,19 +28,22 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.window.ITaskOrganizerController;
+import android.util.SparseArray;
 import android.window.ITaskOrganizer;
+import android.window.ITaskOrganizerController;
 import android.window.IWindowContainer;
 
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.WeakHashMap;
 
@@ -49,6 +53,7 @@
  */
 class TaskOrganizerController extends ITaskOrganizerController.Stub {
     private static final String TAG = "TaskOrganizerController";
+    private static final LinkedList<TaskOrganizerState> EMPTY_LIST = new LinkedList<>();
 
     /**
      * Masks specifying which configurations are important to report back to an organizer when
@@ -71,32 +76,20 @@
         @Override
         public void binderDied() {
             synchronized (mGlobalLock) {
-                final TaskOrganizerState state =
-                    mTaskOrganizerStates.get(mTaskOrganizer.asBinder());
-                state.releaseTasks();
-                mTaskOrganizerStates.remove(mTaskOrganizer.asBinder());
-                if (mTaskOrganizersForWindowingMode.get(mWindowingMode) == mTaskOrganizer) {
-                    mTaskOrganizersForWindowingMode.remove(mWindowingMode);
-                }
+                final TaskOrganizerState state = mTaskOrganizerStates.remove(
+                        mTaskOrganizer.asBinder());
+                state.dispose();
             }
         }
     };
 
-    class TaskOrganizerState {
-        ITaskOrganizer mOrganizer;
-        DeathRecipient mDeathRecipient;
-        int mWindowingMode;
+    private class TaskOrganizerState {
+        private final ITaskOrganizer mOrganizer;
+        private final DeathRecipient mDeathRecipient;
+        private final int mWindowingMode;
+        private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
 
-        ArrayList<Task> mOrganizedTasks = new ArrayList<>();
-
-        // Save the TaskOrganizer which we replaced registration for
-        // so it can be re-registered if we unregister.
-        TaskOrganizerState mReplacementFor;
-        boolean mDisposed = false;
-
-
-        TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
-                @Nullable TaskOrganizerState replacing) {
+        TaskOrganizerState(ITaskOrganizer organizer, int windowingMode) {
             mOrganizer = organizer;
             mDeathRecipient = new DeathRecipient(organizer, windowingMode);
             try {
@@ -105,7 +98,6 @@
                 Slog.e(TAG, "TaskOrganizer failed to register death recipient");
             }
             mWindowingMode = windowingMode;
-            mReplacementFor = replacing;
         }
 
         void addTask(Task t) {
@@ -127,35 +119,26 @@
         }
 
         void dispose() {
-            mDisposed = true;
             releaseTasks();
-            handleReplacement();
+            mTaskOrganizersForWindowingMode.get(mWindowingMode).remove(this);
         }
 
-        void releaseTasks() {
+        private void releaseTasks() {
             for (int i = mOrganizedTasks.size() - 1; i >= 0; i--) {
                 final Task t = mOrganizedTasks.get(i);
-                t.taskOrganizerDied();
                 removeTask(t);
-            }
-        }
-
-        void handleReplacement() {
-            if (mReplacementFor != null && !mReplacementFor.mDisposed) {
-                mTaskOrganizersForWindowingMode.put(mWindowingMode, mReplacementFor);
+                t.taskOrganizerUnregistered();
             }
         }
 
         void unlinkDeath() {
-            mDisposed = true;
             mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
         }
-    };
+    }
 
-
-    final HashMap<Integer, TaskOrganizerState> mTaskOrganizersForWindowingMode = new HashMap();
-    final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap();
-
+    private final SparseArray<LinkedList<TaskOrganizerState>> mTaskOrganizersForWindowingMode =
+            new SparseArray<>();
+    private final HashMap<IBinder, TaskOrganizerState> mTaskOrganizerStates = new HashMap<>();
     private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
     private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
 
@@ -194,11 +177,17 @@
                     Slog.w(TAG, "Task organizer already exists for windowing mode: "
                             + windowingMode);
                 }
-                final TaskOrganizerState previousState =
-                        mTaskOrganizersForWindowingMode.get(windowingMode);
-                final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
-                        previousState);
-                mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+                LinkedList<TaskOrganizerState> states;
+                if (mTaskOrganizersForWindowingMode.contains(windowingMode)) {
+                    states = mTaskOrganizersForWindowingMode.get(windowingMode);
+                } else {
+                    states = new LinkedList<>();
+                    mTaskOrganizersForWindowingMode.put(windowingMode, states);
+                }
+                final TaskOrganizerState previousState = states.peekLast();
+                final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode);
+                states.add(state);
                 mTaskOrganizerStates.put(organizer.asBinder(), state);
 
                 if (previousState == null) {
@@ -219,16 +208,14 @@
 
     @Override
     public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
-        final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
+        final TaskOrganizerState state = mTaskOrganizerStates.remove(organizer.asBinder());
         state.unlinkDeath();
-        if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
-            mTaskOrganizersForWindowingMode.remove(state.mWindowingMode);
-        }
         state.dispose();
     }
 
     ITaskOrganizer getTaskOrganizer(int windowingMode) {
-        final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode);
+        final TaskOrganizerState state = mTaskOrganizersForWindowingMode.get(windowingMode,
+                EMPTY_LIST).peekLast();
         if (state == null) {
             return null;
         }
@@ -255,11 +242,12 @@
                 if (display == null) {
                     return null;
                 }
-                final int nextId = display.getNextStackId();
-                TaskTile tile = new TaskTile(mService, nextId, windowingMode);
-                display.addTile(tile);
-                RunningTaskInfo out = tile.getTaskInfo();
-                mLastSentTaskInfos.put(tile, out);
+
+                final Task task = display.getOrCreateStack(windowingMode, ACTIVITY_TYPE_UNDEFINED,
+                        false /* onTop */, new Intent(), null /* candidateTask */,
+                        true /* createdByOrganizer */);
+                RunningTaskInfo out = task.getTaskInfo();
+                mLastSentTaskInfos.put(task, out);
                 return out;
             }
         } finally {
@@ -273,11 +261,13 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                TaskTile tile = TaskTile.forToken(token.asBinder());
-                if (tile == null) {
-                    return false;
+                final Task task = WindowContainer.fromBinder(token.asBinder()).asTask();
+                if (task == null) return false;
+                if (!task.mCreatedByOrganizer) {
+                    throw new IllegalArgumentException(
+                            "Attempt to delete task not created by organizer task=" + task);
                 }
-                tile.removeImmediately();
+                task.removeImmediately();
                 return true;
             }
         } finally {
@@ -358,12 +348,7 @@
                 if (task == null) {
                     return null;
                 }
-                ActivityStack rootTask = (ActivityStack) task.getRootTask();
-                final TaskTile tile = rootTask.getTile();
-                if (tile != null) {
-                    rootTask = tile;
-                }
-                return rootTask.mRemoteToken;
+                return task.getRootTask().mRemoteToken;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -371,7 +356,7 @@
     }
 
     @Override
-    public void setLaunchRoot(int displayId, @Nullable IWindowContainer tile) {
+    public void setLaunchRoot(int displayId, @Nullable IWindowContainer token) {
         enforceStackPermission("setLaunchRoot()");
         final long origId = Binder.clearCallingIdentity();
         try {
@@ -380,16 +365,21 @@
                 if (display == null) {
                     return;
                 }
-                TaskTile taskTile = tile == null ? null : TaskTile.forToken(tile.asBinder());
-                if (taskTile == null) {
-                    display.mLaunchTile = null;
+                Task task = token == null
+                        ? null : WindowContainer.fromBinder(token.asBinder()).asTask();
+                if (task == null) {
+                    display.mLaunchRootTask = null;
                     return;
                 }
-                if (taskTile.getDisplay() != display) {
-                    throw new RuntimeException("Can't set launch root for display " + displayId
-                            + " to task on display " + taskTile.getDisplay().getDisplayId());
+                if (!task.mCreatedByOrganizer) {
+                    throw new IllegalArgumentException("Attempt to set task not created by "
+                            + "organizer as launch root task=" + task);
                 }
-                display.mLaunchTile = taskTile;
+                if (task.getDisplayContent() != display) {
+                    throw new RuntimeException("Can't set launch root for display " + displayId
+                            + " to task on display " + task.getDisplayContent().getDisplayId());
+                }
+                display.mLaunchRootTask = task;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -411,25 +401,25 @@
                     Slog.e(TAG, "Can't get children of " + parent + " because it is not valid.");
                     return null;
                 }
-                // For now, only support returning children of persistent root tasks (of which the
-                // only current implementation is TaskTile).
-                if (!(container instanceof TaskTile)) {
+                final Task task = container.asTask();
+                if (task == null) {
+                    Slog.e(TAG, container + " is not a task...");
+                    return null;
+                }
+                // For now, only support returning children of tasks created by the organizer.
+                if (!task.mCreatedByOrganizer) {
                     Slog.w(TAG, "Can only get children of root tasks created via createRootTask");
                     return null;
                 }
                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
-                // Tiles aren't real parents, so we need to go through stacks on the display to
-                // ensure correct ordering.
-                final DisplayContent dc = container.getDisplayContent();
-                for (int i = dc.getStackCount() - 1; i >= 0; --i) {
-                    final ActivityStack as = dc.getStackAt(i);
-                    if (as.getTile() == container) {
-                        if (activityTypes != null
-                                && !ArrayUtils.contains(activityTypes, as.getActivityType())) {
-                            continue;
-                        }
-                        out.add(as.getTaskInfo());
+                for (int i = task.getChildCount() - 1; i >= 0; --i) {
+                    final Task child = task.getChildAt(i).asTask();
+                    if (child == null) continue;
+                    if (activityTypes != null
+                            && !ArrayUtils.contains(activityTypes, child.getActivityType())) {
+                        continue;
                     }
+                    out.add(child.getTaskInfo());
                 }
                 return out;
             }
@@ -451,12 +441,7 @@
                 }
                 ArrayList<RunningTaskInfo> out = new ArrayList<>();
                 for (int i = dc.getStackCount() - 1; i >= 0; --i) {
-                    final ActivityStack task = dc.getStackAt(i);
-                    if (task.getTile() != null) {
-                        // a tile is supposed to look like a parent, so don't include their
-                        // "children" here. They can be accessed via getChildTasks()
-                        continue;
-                    }
+                    final Task task = dc.getStackAt(i);
                     if (activityTypes != null
                             && !ArrayUtils.contains(activityTypes, task.getActivityType())) {
                         continue;
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f046e8a..be0d6f8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -268,8 +268,9 @@
         mDisplayContent.getDisplayRotation().pause();
 
         // Notify InputMonitor to take mDragWindowHandle.
-        mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
-        new SurfaceControl.Transaction().syncInputWindows().apply(true);
+        final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
+        mDisplayContent.getInputMonitor().updateInputWindowsImmediately(t);
+        t.syncInputWindows().apply();
 
         final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
deleted file mode 100644
index 51142b1..0000000
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-
-import android.app.ActivityManager;
-import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.IBinder;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.function.Consumer;
-
-/**
- * A Tile. Right now this acts as a proxy for manipulating non-child stacks. Eventually, this
- * can become an actual parent.
- */
-// TODO(task-hierarchy): Remove when tasks can nest >2 or when single tasks can handle their
-//                       own lifecycles.
-public class TaskTile extends ActivityStack {
-    private static final String TAG = "TaskTile";
-    final ArrayList<WindowContainer> mChildren = new ArrayList<>();
-
-    private static ActivityInfo createEmptyActivityInfo() {
-        ActivityInfo info = new ActivityInfo();
-        info.applicationInfo = new ApplicationInfo();
-        return info;
-    }
-
-    TaskTile(ActivityTaskManagerService atmService, int id, int windowingMode) {
-        super(atmService, id, new Intent() /*intent*/,  null /*affinityIntent*/, null /*affinity*/,
-                null /*rootAffinity*/, null /*realActivity*/, null /*origActivity*/,
-                false /*rootWasReset*/, false /*autoRemoveRecents*/, false /*askedCompatMode*/,
-                0 /*userId*/, 0 /*effectiveUid*/, null /*lastDescription*/,
-                System.currentTimeMillis(), true /*neverRelinquishIdentity*/,
-                new ActivityManager.TaskDescription(), id, INVALID_TASK_ID, INVALID_TASK_ID,
-                0 /*taskAffiliationColor*/, 0 /*callingUid*/, "" /*callingPackage*/,
-                null /*callingFeatureId*/, RESIZE_MODE_RESIZEABLE,
-                false /*supportsPictureInPicture*/, false /*_realActivitySuspended*/,
-                false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE,
-                createEmptyActivityInfo(), null /*voiceSession*/, null /*voiceInteractor*/,
-                null /*stack*/);
-        getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
-    }
-
-    @Override
-    void onDisplayChanged(DisplayContent dc) {
-        mDisplayContent = null;
-        if (dc != null) {
-            dc.getPendingTransaction().merge(getPendingTransaction());
-        }
-        mDisplayContent = dc;
-        // Virtual parent, so don't notify children.
-    }
-
-    @Override
-    TaskTile asTile() {
-        return this;
-    }
-
-    @Override
-    protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
-        throw new RuntimeException("Improper use of addChild() on Tile");
-    }
-
-    @Override
-    void addChild(WindowContainer child, int index) {
-        mChildren.add(child);
-        if (child instanceof ActivityStack) {
-            ((ActivityStack) child).setTile(this);
-        }
-        mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
-                this, false /* force */);
-    }
-
-    @Override
-    void removeChild(WindowContainer child) {
-        if (child instanceof ActivityStack) {
-            ((ActivityStack) child).setTile(null);
-        }
-        mChildren.remove(child);
-        mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
-                this, false /* force */);
-    }
-
-    void removeAllChildren() {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer child = mChildren.get(i);
-            if (child instanceof ActivityStack) {
-                ((ActivityStack) child).setTile(null);
-            }
-        }
-        mChildren.clear();
-        mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
-                this, false /* force */);
-    }
-
-    @Override
-    protected int getChildCount() {
-        // Currently 0 as this isn't a proper hierarchy member yet.
-        return 0;
-    }
-
-    @Override
-    public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
-        Configuration c = new Configuration(getRequestedOverrideConfiguration());
-        c.windowConfiguration.setWindowingMode(windowingMode);
-        onRequestedOverrideConfigurationChanged(c);
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        super.onConfigurationChanged(newParentConfig);
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer child = mChildren.get(i);
-            child.onConfigurationChanged(child.getParent().getConfiguration());
-        }
-    }
-
-    void forAllTileActivities(Consumer<ActivityRecord> callback) {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            mChildren.get(i).forAllActivities(callback, true /* traverseTopToBottom */);
-        }
-    }
-
-    /**
-     * Until this can be part of the hierarchy, the Stack level can use this utility during
-     * resolveOverrideConfig to simulate inheritance.
-     */
-    void updateResolvedConfig(Configuration inOutResolvedConfig) {
-        Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
-        if (resolveBounds.isEmpty()) {
-            resolveBounds.set(getRequestedOverrideBounds());
-        }
-        int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
-        if (stackMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
-                || stackMode == WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
-            // Also replace FULLSCREEN because we interpret FULLSCREEN as "fill parent"
-            inOutResolvedConfig.windowConfiguration.setWindowingMode(
-                    getRequestedOverrideWindowingMode());
-        }
-        if (inOutResolvedConfig.smallestScreenWidthDp
-                == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
-            inOutResolvedConfig.smallestScreenWidthDp =
-                    getRequestedOverrideConfiguration().smallestScreenWidthDp;
-        }
-        if (inOutResolvedConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-            inOutResolvedConfig.screenWidthDp = getRequestedOverrideConfiguration().screenWidthDp;
-        }
-        if (inOutResolvedConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-            inOutResolvedConfig.screenHeightDp = getRequestedOverrideConfiguration().screenHeightDp;
-        }
-        Rect resolveAppBounds = inOutResolvedConfig.windowConfiguration.getAppBounds();
-        if (resolveAppBounds == null || resolveAppBounds.isEmpty()) {
-            inOutResolvedConfig.windowConfiguration.setAppBounds(
-                    getRequestedOverrideConfiguration().windowConfiguration.getAppBounds());
-        }
-    }
-
-    @Override
-    void fillTaskInfo(TaskInfo info) {
-        super.fillTaskInfo(info);
-        WindowContainer top = null;
-        // Check mChildren.isEmpty directly because hasChild() -> getChildCount() always returns 0
-        if (!mChildren.isEmpty()) {
-            // Find the top-most root task which is a virtual child of this Tile. Because this is a
-            // virtual parent, the mChildren order here isn't changed during hierarchy operations.
-            WindowContainer parent = mChildren.get(0).getParent();
-            for (int i = parent.getChildCount() - 1; i >= 0; --i) {
-                if (mChildren.contains(parent.getChildAt(i))) {
-                    top = parent.getChildAt(i);
-                    break;
-                }
-            }
-        }
-        final Task topTask = top == null ? null : top.getTopMostTask();
-        boolean isResizable = topTask == null || topTask.isResizeable();
-        info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
-        info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
-    }
-
-    @Override
-    void removeImmediately() {
-        removeAllChildren();
-        super.removeImmediately();
-    }
-
-    @Override
-    void taskOrganizerDied() {
-        super.taskOrganizerDied();
-        removeImmediately();
-    }
-
-    static TaskTile forToken(IBinder token) {
-        try {
-            return (TaskTile) ((RemoteToken) token).getContainer();
-        } catch (ClassCastException e) {
-            Slog.w(TAG, "Bad tile token: " + token, e);
-            return null;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 57d0a33..29a2e18 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -142,11 +142,13 @@
             mFindResults.setUseTopWallpaperAsTarget(true);
         }
 
-        final boolean keyguardGoingAwayWithWallpaper = (w.mActivityRecord != null
-                && w.mActivityRecord.isAnimating(TRANSITION | PARENTS)
-                && AppTransition.isKeyguardGoingAwayTransit(w.mActivityRecord.getTransit())
-                && (w.mActivityRecord.getTransitFlags()
-                        & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
+        final WindowContainer animatingContainer = w.mActivityRecord != null
+                ? w.mActivityRecord.getAnimatingContainer() : null;
+        final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null
+                && animatingContainer.isAnimating(TRANSITION | PARENTS)
+                && AppTransition.isKeyguardGoingAwayTransit(animatingContainer.mTransit)
+                && (animatingContainer.mTransitFlags
+                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
 
         boolean needsShowWhenLockedWallpaper = false;
         if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
@@ -166,8 +168,6 @@
 
         final RecentsAnimationController recentsAnimationController =
                 mService.getRecentsAnimationController();
-        final WindowContainer animatingContainer =
-                w.mActivityRecord != null ? w.mActivityRecord.getAnimatingContainer() : null;
         final boolean animationWallpaper = animatingContainer != null
                 && animatingContainer.getAnimation() != null
                 && animatingContainer.getAnimation().getShowWallpaper();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 23ba528..0757725 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7746,19 +7746,23 @@
     public void syncInputTransactions() {
         waitForAnimationsToComplete();
 
+        // Collect all input transactions from all displays to make sure we could sync all input
+        // windows at same time.
+        final SurfaceControl.Transaction t = mTransactionFactory.get();
         synchronized (mGlobalLock) {
             mWindowPlacerLocked.performSurfacePlacementIfScheduled();
             mRoot.forAllDisplays(displayContent ->
-                    displayContent.getInputMonitor().updateInputWindowsImmediately());
+                    displayContent.getInputMonitor().updateInputWindowsImmediately(t));
         }
 
-        mTransactionFactory.get().syncInputWindows().apply(true);
+        t.syncInputWindows().apply();
     }
 
     private void waitForAnimationsToComplete() {
         synchronized (mGlobalLock) {
             long timeoutRemaining = ANIMATION_COMPLETED_TIMEOUT_MS;
-            while (mRoot.isAnimating(TRANSITION | CHILDREN) && timeoutRemaining > 0) {
+            while ((mAnimator.isAnimationScheduled()
+                    || mRoot.isAnimating(TRANSITION | CHILDREN)) && timeoutRemaining > 0) {
                 long startTime = System.currentTimeMillis();
                 try {
                     mGlobalLock.wait(timeoutRemaining);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index e416e80..5f21e17 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -159,17 +159,7 @@
                                 false /* preserveWindow */);
                         try {
                             for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
-                                final WindowContainer wc = haveConfigChanges.valueAt(i);
-                                final Task task = wc.asTask();
-                                final TaskTile tile = task != null ? task.asTile() : null;
-                                if (tile != null) {
-                                    // Special case for tile. Can't override normal forAllActivities
-                                    // because it generates duplicate calls and messes up existing
-                                    // code-paths.
-                                    tile.forAllTileActivities(f);
-                                } else {
-                                    wc.forAllActivities(f);
-                                }
+                                haveConfigChanges.valueAt(i).forAllActivities(f);
                             }
                         } finally {
                             f.recycle();
@@ -223,51 +213,65 @@
 
     private int sanitizeAndApplyHierarchyOp(WindowContainer container,
             WindowContainerTransaction.HierarchyOp hop) {
-        if (!(container instanceof Task)) {
+        final Task task = container.asTask();
+        if (task == null) {
             throw new IllegalArgumentException("Invalid container in hierarchy op");
         }
-        if (container.getDisplayContent() == null) {
-            Slog.w(TAG, "Container is no longer attached: " + container);
+        final DisplayContent dc = task.getDisplayContent();
+        if (dc == null) {
+            Slog.w(TAG, "Container is no longer attached: " + task);
             return 0;
         }
+        final ActivityStack as = (ActivityStack) task;
+
         if (hop.isReparent()) {
-            // special case for tiles since they are "virtual" parents
-            if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
-                ActivityStack as = (ActivityStack) container;
-                TaskTile newParent = hop.getNewParent() == null ? null
-                        : (TaskTile) WindowContainer.fromBinder(hop.getNewParent());
-                if (as.getTile() != newParent) {
-                    if (as.getTile() != null) {
-                        as.getTile().removeChild(as);
+            final boolean isNonOrganizedRootableTask =
+                    (task.isRootTask() && !task.mCreatedByOrganizer)
+                            || task.getParent().asTask().mCreatedByOrganizer;
+            if (isNonOrganizedRootableTask) {
+                Task newParent = hop.getNewParent() == null ? null
+                        : WindowContainer.fromBinder(hop.getNewParent()).asTask();
+                if (task.getParent() != newParent) {
+                    if (newParent == null) {
+                        // Re-parent task to display as a root task.
+                        dc.moveStackToDisplay(as, hop.getToTop());
+                    } else if (newParent.inMultiWindowMode() && !task.isResizeable()
+                            && task.isLeafTask()) {
+                        Slog.w(TAG, "Can't support task that doesn't support multi-window mode in"
+                                + " multi-window mode... newParent=" + newParent + " task=" + task);
+                        return 0;
+                    } else {
+                        // Clear the window crop on root task since it may not be updated after
+                        // reparent (no longer be a root task)
+                        task.getSurfaceControl().setWindowCrop(null);
+                        task.reparent((ActivityStack) newParent,
+                                hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+                                false /*moveParents*/, "sanitizeAndApplyHierarchyOp");
                     }
-                    if (newParent != null) {
-                        if (!as.affectedBySplitScreenResize()) {
-                            return 0;
-                        }
-                        newParent.addChild(as, POSITION_TOP);
-                    }
-                }
-                if (hop.getToTop()) {
-                    as.getDisplay().positionStackAtTop(as, false /* includingParents */);
                 } else {
-                    as.getDisplay().positionStackAtBottom(as);
+                    final ActivityStack rootTask =
+                            (ActivityStack) (newParent != null ? newParent : task.getRootTask());
+                    if (hop.getToTop()) {
+                        as.getDisplay().positionStackAtTop(rootTask, false /* includingParents */);
+                    } else {
+                        as.getDisplay().positionStackAtBottom(rootTask);
+                    }
                 }
-            } else if (container instanceof Task) {
+            } else {
                 throw new RuntimeException("Reparenting leaf Tasks is not supported now.");
             }
         } else {
             // Ugh, of course ActivityStack has its own special reorder logic...
-            if (container instanceof ActivityStack && ((ActivityStack) container).isRootTask()) {
-                ActivityStack as = (ActivityStack) container;
+            if (task.isRootTask()) {
                 if (hop.getToTop()) {
-                    as.getDisplay().positionStackAtTop(as, false /* includingParents */);
+                    dc.positionStackAtTop(as, false /* includingParents */);
                 } else {
-                    as.getDisplay().positionStackAtBottom(as);
+                    dc.positionStackAtBottom(as);
                 }
             } else {
-                container.getParent().positionChildAt(
+                task.getParent().positionChildAt(
                         hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
-                        container, false /* includingParents */);
+                        task, false /* includingParents */);
             }
         }
         return TRANSACT_EFFECTS_LIFECYCLE;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 161152b..c4d700c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -131,6 +131,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
 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_STATE_BLAST_SYNC_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
@@ -138,7 +139,6 @@
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_REMOVING_FOCUS;
 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.H.WINDOW_STATE_BLAST_SYNC_TIMEOUT;
 import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
@@ -608,6 +608,11 @@
     boolean mSeamlesslyRotated = false;
 
     /**
+     * Indicates if this window is behind IME. Only windows behind IME can get insets from IME.
+     */
+    boolean mBehindIme = false;
+
+    /**
      * Surface insets from the previous call to relayout(), used to track
      * if we are changing the Surface insets.
      */
@@ -2270,9 +2275,9 @@
             return false;
         }
 
-        if (PixelFormat.formatHasAlpha(mAttrs.format) && mAttrs.alpha == 0) {
-            // Support legacy use cases where completely transparent windows can still be ime target
-            // with FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
+        if (PixelFormat.formatHasAlpha(mAttrs.format)) {
+            // Support legacy use cases where transparent windows can still be ime target with
+            // FLAG_NOT_FOCUSABLE and ALT_FOCUSABLE_IM set.
             // Certain apps listen for IME insets using transparent windows and ADJUST_NOTHING to
             // manually synchronize app content to IME animation b/144619551.
             // TODO(b/145812508): remove this once new focus management is complete b/141738570
@@ -3338,7 +3343,7 @@
         }
 
         final ActivityStack stack = task.getStack();
-        if (stack == null) {
+        if (stack == null || stack.mCreatedByOrganizer) {
             return;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 850c362..3c2b6ec 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -480,26 +480,42 @@
     }
 
     /**
-     * Clears the transformation and continue updating the orientation change of display. Only the
-     * state owner can clear the transform state.
+     * Finishes the transform and continue updating the orientation change of display. Only the
+     * state owner can finish the transform state.
      */
-    void clearFixedRotationTransform() {
-        final FixedRotationTransformState state = mFixedRotationTransformState;
-        if (state == null || state.mOwner != this) {
+    void finishFixedRotationTransform() {
+        if (mFixedRotationTransformState == null || mFixedRotationTransformState.mOwner != this) {
             return;
         }
-        state.resetTransform();
-        // Clear the flag so if the display will be updated to the same orientation, the transform
-        // won't take effect. The state is cleared at the end, because it is used to indicate that
-        // other windows can use seamless rotation when applying rotation to display.
-        state.mIsTransforming = false;
         final boolean changed =
                 mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(this);
-        // If it is not the launching app or the display is not rotated, make sure the merged
-        // override configuration is restored from parent.
+        // If it is not the launching app or the display is not rotated, make sure the transform is
+        // cleared and the configuration is restored from parent.
         if (!changed) {
-            onMergedOverrideConfigurationChanged();
+            clearFixedRotationTransform(null /* applyDisplayRotation */);
+            onConfigurationChanged(getParent().getConfiguration());
         }
+    }
+
+    /**
+     * Clears the transform and apply display rotation if the action is given. The caller needs to
+     * refresh the configuration of this container after this method call.
+     */
+    void clearFixedRotationTransform(Runnable applyDisplayRotation) {
+        final FixedRotationTransformState state = mFixedRotationTransformState;
+        if (state == null) {
+            return;
+        }
+
+        state.resetTransform();
+        // Clear the flag so if the display will be updated to the same orientation, the transform
+        // won't take effect.
+        state.mIsTransforming = false;
+        if (applyDisplayRotation != null) {
+            applyDisplayRotation.run();
+        }
+        // The state is cleared at the end, because it is used to indicate that other windows can
+        // use seamless rotation when applying rotation to display.
         for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) {
             state.mAssociatedTokens.get(i).mFixedRotationTransformState = null;
         }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e3f9ae8..9bc5d34 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -206,7 +206,7 @@
     status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
     status_t pilferPointers(const sp<IBinder>& token);
 
-    void setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray, int32_t displayId);
+    void displayRemoved(JNIEnv* env, int32_t displayId);
     void setFocusedApplication(JNIEnv* env, int32_t displayId, jobject applicationHandleObj);
     void setFocusedDisplay(JNIEnv* env, int32_t displayId);
     void setInputDispatchMode(bool enabled, bool frozen);
@@ -771,55 +771,10 @@
     }
 }
 
-void NativeInputManager::setInputWindows(JNIEnv* env, jobjectArray windowHandleObjArray,
-         int32_t displayId) {
-    std::vector<sp<InputWindowHandle> > windowHandles;
-
-    if (windowHandleObjArray) {
-        jsize length = env->GetArrayLength(windowHandleObjArray);
-        for (jsize i = 0; i < length; i++) {
-            jobject windowHandleObj = env->GetObjectArrayElement(windowHandleObjArray, i);
-            if (! windowHandleObj) {
-                break; // found null element indicating end of used portion of the array
-            }
-
-            sp<InputWindowHandle> windowHandle =
-                    android_view_InputWindowHandle_getHandle(env, windowHandleObj);
-            if (windowHandle != nullptr) {
-                windowHandles.push_back(windowHandle);
-            }
-            env->DeleteLocalRef(windowHandleObj);
-        }
-    }
-
-    mInputManager->getDispatcher()->setInputWindows(windowHandles, displayId);
-
-    // Do this after the dispatcher has updated the window handle state.
-    bool newPointerGesturesEnabled = true;
-    size_t numWindows = windowHandles.size();
-    for (size_t i = 0; i < numWindows; i++) {
-        const sp<InputWindowHandle>& windowHandle = windowHandles[i];
-        const InputWindowInfo* windowInfo = windowHandle->getInfo();
-        if (windowInfo && windowInfo->hasFocus && (windowInfo->inputFeatures
-                & InputWindowInfo::INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES)) {
-            newPointerGesturesEnabled = false;
-        }
-    }
-
-    bool pointerGesturesEnabledChanged = false;
-    { // acquire lock
-        AutoMutex _l(mLock);
-
-        if (mLocked.pointerGesturesEnabled != newPointerGesturesEnabled) {
-            mLocked.pointerGesturesEnabled = newPointerGesturesEnabled;
-            pointerGesturesEnabledChanged = true;
-        }
-    } // release lock
-
-    if (pointerGesturesEnabledChanged) {
-        mInputManager->getReader()->requestRefreshConfiguration(
-                InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT);
-    }
+void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
+    // Set an empty list to remove all handles from the specific display.
+    std::vector<sp<InputWindowHandle>> windowHandles;
+    mInputManager->getDispatcher()->setInputWindows({{displayId, windowHandles}});
 }
 
 void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
@@ -1567,11 +1522,10 @@
     im->getInputManager()->getReader()->toggleCapsLockState(deviceId);
 }
 
-static void nativeSetInputWindows(JNIEnv* env, jclass /* clazz */,
-        jlong ptr, jobjectArray windowHandleObjArray, jint displayId) {
+static void nativeDisplayRemoved(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
-    im->setInputWindows(env, windowHandleObjArray, displayId);
+    im->displayRemoved(env, displayId);
 }
 
 static void nativeSetFocusedApplication(JNIEnv* env, jclass /* clazz */,
@@ -1815,8 +1769,7 @@
         {"nativeVerifyInputEvent", "(JLandroid/view/InputEvent;)Landroid/view/VerifiedInputEvent;",
          (void*)nativeVerifyInputEvent},
         {"nativeToggleCapsLock", "(JI)V", (void*)nativeToggleCapsLock},
-        {"nativeSetInputWindows", "(J[Landroid/view/InputWindowHandle;I)V",
-         (void*)nativeSetInputWindows},
+        {"nativeDisplayRemoved", "(JI)V", (void*)nativeDisplayRemoved},
         {"nativeSetFocusedApplication", "(JILandroid/view/InputApplicationHandle;)V",
          (void*)nativeSetFocusedApplication},
         {"nativeSetFocusedDisplay", "(JI)V", (void*)nativeSetFocusedDisplay},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 023a1e8..e304bca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4434,6 +4434,11 @@
                     clearDeviceOwnerLocked(getDeviceOwnerAdminLocked(), userHandle);
                 }
                 if (isProfileOwner(adminReceiver, userHandle)) {
+                    if (isProfileOwnerOfOrganizationOwnedDevice(userHandle)) {
+                        mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
+                                false,
+                                UserHandle.of(getProfileParentId(userHandle)));
+                    }
                     final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver,
                             userHandle, /* parent */ false);
                     clearProfileOwnerLocked(admin, userHandle);
@@ -7166,7 +7171,9 @@
         ActiveAdmin admin;
         synchronized (getLockObject()) {
             if (who == null) {
-                if ((frpManagementAgentUid != mInjector.binderGetCallingUid())) {
+                if ((frpManagementAgentUid != mInjector.binderGetCallingUid())
+                        && (mContext.checkCallingPermission(permission.MASTER_CLEAR)
+                        != PackageManager.PERMISSION_GRANTED)) {
                     throw new SecurityException(
                             "Must be called by the FRP management agent on device");
                 }
@@ -13070,26 +13077,25 @@
             final boolean addingProfileRestricted = mUserManager.hasUserRestriction(
                     UserManager.DISALLOW_ADD_MANAGED_PROFILE, callingUserHandle);
 
-            UserInfo parentUser = mUserManager.getProfileParent(callingUserId);
-            final boolean addingProfileRestrictedOnParent = (parentUser != null)
-                    && mUserManager.hasUserRestriction(
-                            UserManager.DISALLOW_ADD_MANAGED_PROFILE,
-                            UserHandle.of(parentUser.id));
+            if (mUserManager.getUserInfo(callingUserId).isProfile()) {
+                Slog.i(LOG_TAG,
+                        String.format("Calling user %d is a profile, cannot add another.",
+                                callingUserId));
+                // The check is called from inside a managed profile. A managed profile cannot
+                // be provisioned from within another managed profile.
+                return CODE_CANNOT_ADD_MANAGED_PROFILE;
+            }
 
-            Slog.i(LOG_TAG, String.format(
-                    "When checking for managed profile provisioning: Has device owner? %b, adding"
-                            + " profile restricted? %b, adding profile restricted on parent? %b",
-                    hasDeviceOwner, addingProfileRestricted, addingProfileRestrictedOnParent));
-
-            // If there's a device owner, the restriction on adding a managed profile must be set
-            // somewhere.
-            if (hasDeviceOwner && !addingProfileRestricted && !addingProfileRestrictedOnParent) {
+            // If there's a device owner, the restriction on adding a managed profile must be set.
+            if (hasDeviceOwner && !addingProfileRestricted) {
                 Slog.wtf(LOG_TAG, "Has a device owner but no restriction on adding a profile.");
             }
 
-            // Do not allow adding a managed profile if there's a restriction, either on the current
-            // user or its parent user.
-            if (addingProfileRestricted || addingProfileRestrictedOnParent) {
+            // Do not allow adding a managed profile if there's a restriction.
+            if (addingProfileRestricted) {
+                Slog.i(LOG_TAG, String.format(
+                        "Adding a profile is restricted: User %s Has device owner? %b",
+                        callingUserHandle, hasDeviceOwner));
                 return CODE_CANNOT_ADD_MANAGED_PROFILE;
             }
             // If there's a restriction on removing the managed profile then we have to take it
@@ -13098,6 +13104,8 @@
                     !mUserManager.hasUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                     callingUserHandle);
             if (!mUserManager.canAddMoreManagedProfiles(callingUserId, canRemoveProfile)) {
+                Slog.i(LOG_TAG, String.format(
+                        "Cannot add more profiles: Can remove current? %b", canRemoveProfile));
                 return CODE_CANNOT_ADD_MANAGED_PROFILE;
             }
         } finally {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b019e9d..c631eeb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -144,7 +144,6 @@
 import com.android.server.recoverysystem.RecoverySystemService;
 import com.android.server.restrictions.RestrictionsManagerService;
 import com.android.server.role.RoleManagerService;
-import com.android.server.rollback.RollbackManagerService;
 import com.android.server.security.FileIntegrityService;
 import com.android.server.security.KeyAttestationApplicationIdProviderService;
 import com.android.server.security.KeyChainSystemService;
@@ -294,6 +293,8 @@
             "com.android.server.DeviceIdleController";
     private static final String BLOB_STORE_MANAGER_SERVICE_CLASS =
             "com.android.server.blob.BlobStoreManagerService";
+    private static final String ROLLBACK_MANAGER_SERVICE_CLASS =
+            "com.android.server.rollback.RollbackManagerService";
 
     private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
 
@@ -964,7 +965,7 @@
 
         // Manages apk rollbacks.
         t.traceBegin("StartRollbackManagerService");
-        mSystemServiceManager.startService(RollbackManagerService.class);
+        mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
         // Service to capture bugreports.
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index ae8d5743..136ee91 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -26,6 +26,7 @@
 import android.app.Person;
 import android.app.prediction.AppTarget;
 import android.app.prediction.AppTargetEvent;
+import android.app.usage.UsageEvents;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -70,6 +71,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
@@ -237,6 +239,27 @@
         eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType));
     }
 
+    /**
+     * Queries events for moving app to foreground between {@code startTime} and {@code endTime}.
+     */
+    @NonNull
+    public List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int callingUserId,
+            long startTime, long endTime) {
+        return UsageStatsQueryHelper.queryAppMovingToForegroundEvents(callingUserId, startTime,
+                endTime);
+    }
+
+    /**
+     * Queries launch counts of apps within {@code packageNameFilter} between {@code startTime}
+     * and {@code endTime}.
+     */
+    @NonNull
+    public Map<String, Integer> queryAppLaunchCount(@UserIdInt int callingUserId, long startTime,
+            long endTime, Set<String> packageNameFilter) {
+        return UsageStatsQueryHelper.queryAppLaunchCount(callingUserId, startTime, endTime,
+                packageNameFilter);
+    }
+
     /** Prunes the data for the specified user. */
     public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) {
         UserData userData = getUnlockedUserData(userId);
@@ -382,7 +405,13 @@
         }
     }
 
-    private int mimeTypeToShareEventType(String mimeType) {
+    /**
+     * Converts {@code mimeType} to {@link Event.EventType}.
+     */
+    public int mimeTypeToShareEventType(String mimeType) {
+        if (mimeType == null) {
+            return Event.TYPE_SHARE_OTHER;
+        }
         if (mimeType.startsWith("text/")) {
             return Event.TYPE_SHARE_TEXT;
         } else if (mimeType.startsWith("image/")) {
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
index 72f1abb..6e6fea9 100644
--- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
 import android.content.LocusId;
@@ -27,7 +29,10 @@
 
 import com.android.server.LocalServices;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Function;
 
 /** A helper class that queries {@link UsageStatsManagerInternal}. */
@@ -46,7 +51,7 @@
      */
     UsageStatsQueryHelper(@UserIdInt int userId,
             Function<String, PackageData> packageDataGetter) {
-        mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
+        mUsageStatsManagerInternal = getUsageStatsManagerInternal();
         mUserId = userId;
         mPackageDataGetter = packageDataGetter;
     }
@@ -106,6 +111,53 @@
         return mLastEventTimestamp;
     }
 
+    /**
+     * Queries {@link UsageStatsManagerInternal} events for moving app to foreground between
+     * {@code startTime} and {@code endTime}.
+     *
+     * @return a list containing events moving app to foreground.
+     */
+    static List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int userId,
+            long startTime, long endTime) {
+        List<UsageEvents.Event> res = new ArrayList<>();
+        UsageEvents usageEvents = getUsageStatsManagerInternal().queryEventsForUser(userId,
+                startTime, endTime,
+                UsageEvents.HIDE_SHORTCUT_EVENTS | UsageEvents.HIDE_LOCUS_EVENTS);
+        if (usageEvents == null) {
+            return res;
+        }
+        while (usageEvents.hasNextEvent()) {
+            UsageEvents.Event e = new UsageEvents.Event();
+            usageEvents.getNextEvent(e);
+            if (e.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) {
+                res.add(e);
+            }
+        }
+        return res;
+    }
+
+    /**
+     * Queries {@link UsageStatsManagerInternal} for launch count of apps within {@code
+     * packageNameFilter} between {@code startTime} and {@code endTime}.obfuscateInstantApps
+     *
+     * @return a map which keys are package names and values are app launch counts.
+     */
+    static Map<String, Integer> queryAppLaunchCount(@UserIdInt int userId, long startTime,
+            long endTime, Set<String> packageNameFilter) {
+        List<UsageStats> stats = getUsageStatsManagerInternal().queryUsageStatsForUser(userId,
+                UsageStatsManager.INTERVAL_BEST, startTime, endTime,
+                /* obfuscateInstantApps= */ false);
+        Map<String, Integer> aggregatedStats = new ArrayMap<>();
+        for (UsageStats stat : stats) {
+            String packageName = stat.getPackageName();
+            if (packageNameFilter.contains(packageName)) {
+                aggregatedStats.put(packageName,
+                        aggregatedStats.getOrDefault(packageName, 0) + stat.getAppLaunchCount());
+            }
+        }
+        return aggregatedStats;
+    }
+
     private void onInAppConversationEnded(@NonNull PackageData packageData,
             @NonNull UsageEvents.Event endEvent) {
         ComponentName activityName =
@@ -138,4 +190,8 @@
                 EventStore.CATEGORY_LOCUS_ID_BASED, locusId.getId());
         eventHistory.addEvent(event);
     }
+
+    private static UsageStatsManagerInternal getUsageStatsManagerInternal() {
+        return LocalServices.getService(UsageStatsManagerInternal.class);
+    }
 }
diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
index 8e5d75b..d09d0b3 100644
--- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
+++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java
@@ -27,13 +27,11 @@
 import android.content.IntentFilter;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutManager.ShareShortcutInfo;
-import android.util.Range;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ChooserActivity;
 import com.android.server.people.data.ConversationInfo;
 import com.android.server.people.data.DataManager;
-import com.android.server.people.data.Event;
 import com.android.server.people.data.EventHistory;
 import com.android.server.people.data.PackageData;
 
@@ -42,6 +40,9 @@
 import java.util.List;
 import java.util.function.Consumer;
 
+/**
+ * Predictor that predicts the {@link AppTarget} the user is most likely to open on share sheet.
+ */
 class ShareTargetPredictor extends AppTargetPredictor {
 
     private final IntentFilter mIntentFilter;
@@ -66,7 +67,9 @@
     @Override
     void predictTargets() {
         List<ShareTarget> shareTargets = getDirectShareTargets();
-        rankTargets(shareTargets);
+        SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter),
+                System.currentTimeMillis());
+        Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
         List<AppTarget> res = new ArrayList<>();
         for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(),
                 shareTargets.size()); i++) {
@@ -80,36 +83,16 @@
     @Override
     void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) {
         List<ShareTarget> shareTargets = getAppShareTargets(targets);
-        rankTargets(shareTargets);
+        SharesheetModelScorer.computeScoreForAppShare(shareTargets,
+                getShareEventType(mIntentFilter), getPredictionContext().getPredictedTargetCount(),
+                System.currentTimeMillis(), getDataManager(),
+                mCallingUserId);
+        Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore()));
         List<AppTarget> appTargetList = new ArrayList<>();
         shareTargets.forEach(t -> appTargetList.add(t.getAppTarget()));
         callback.accept(appTargetList);
     }
 
-    private void rankTargets(List<ShareTarget> shareTargets) {
-        // Rank targets based on recency of sharing history only for the moment.
-        // TODO: Take more factors into ranking, e.g. frequency, mime type, foreground app.
-        Collections.sort(shareTargets, (t1, t2) -> {
-            if (t1.getEventHistory() == null) {
-                return 1;
-            }
-            if (t2.getEventHistory() == null) {
-                return -1;
-            }
-            Range<Long> timeSlot1 = t1.getEventHistory().getEventIndex(
-                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
-            Range<Long> timeSlot2 = t2.getEventHistory().getEventIndex(
-                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
-            if (timeSlot1 == null) {
-                return 1;
-            } else if (timeSlot2 == null) {
-                return -1;
-            } else {
-                return -Long.compare(timeSlot1.getUpper(), timeSlot2.getUpper());
-            }
-        });
-    }
-
     private List<ShareTarget> getDirectShareTargets() {
         List<ShareTarget> shareTargets = new ArrayList<>();
         List<ShareShortcutInfo> shareShortcuts =
@@ -153,6 +136,11 @@
         return shareTargets;
     }
 
+    private int getShareEventType(IntentFilter intentFilter) {
+        String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
+        return getDataManager().mimeTypeToShareEventType(mimeType);
+    }
+
     @VisibleForTesting
     static class ShareTarget {
 
@@ -162,13 +150,16 @@
         private final EventHistory mEventHistory;
         @Nullable
         private final ConversationInfo mConversationInfo;
+        private float mScore;
 
-        private ShareTarget(@NonNull AppTarget appTarget,
+        @VisibleForTesting
+        ShareTarget(@NonNull AppTarget appTarget,
                 @Nullable EventHistory eventHistory,
                 @Nullable ConversationInfo conversationInfo) {
             mAppTarget = appTarget;
             mEventHistory = eventHistory;
             mConversationInfo = conversationInfo;
+            mScore = 0f;
         }
 
         @NonNull
@@ -188,5 +179,15 @@
         ConversationInfo getConversationInfo() {
             return mConversationInfo;
         }
+
+        @VisibleForTesting
+        float getScore() {
+            return mScore;
+        }
+
+        @VisibleForTesting
+        void setScore(float score) {
+            mScore = score;
+        }
     }
 }
diff --git a/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
new file mode 100644
index 0000000..0ac5724
--- /dev/null
+++ b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.people.prediction;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.usage.UsageEvents;
+import android.util.ArrayMap;
+import android.util.Pair;
+import android.util.Range;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ChooserActivity;
+import com.android.server.people.data.DataManager;
+import com.android.server.people.data.Event;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.concurrent.TimeUnit;
+
+/** Ranking scorer for Sharesheet targets. */
+class SharesheetModelScorer {
+
+    private static final String TAG = "SharesheetModelScorer";
+    private static final boolean DEBUG = false;
+    private static final Integer RECENCY_SCORE_COUNT = 6;
+    private static final float RECENCY_INITIAL_BASE_SCORE = 0.4F;
+    private static final float RECENCY_SCORE_INITIAL_DECAY = 0.05F;
+    private static final float RECENCY_SCORE_SUBSEQUENT_DECAY = 0.02F;
+    private static final long ONE_MONTH_WINDOW = TimeUnit.DAYS.toMillis(30);
+    private static final long FOREGROUND_APP_PROMO_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10);
+    private static final float FREQUENTLY_USED_APP_SCORE_DECAY = 0.9F;
+    @VisibleForTesting
+    static final float FOREGROUND_APP_WEIGHT = 0F;
+    @VisibleForTesting
+    static final String CHOOSER_ACTIVITY = ChooserActivity.class.getSimpleName();
+
+    // Keep constructor private to avoid class being instantiated.
+    private SharesheetModelScorer() {
+    }
+
+    /**
+     * Computes each target's recency, frequency and frequency of the same {@code shareEventType}
+     * based on past sharing history. Update {@link ShareTargetPredictor.ShareTargetScore}.
+     */
+    static void computeScore(List<ShareTargetPredictor.ShareTarget> shareTargets,
+            int shareEventType, long now) {
+        if (shareTargets.isEmpty()) {
+            return;
+        }
+        float totalFreqScore = 0f;
+        int freqScoreCount = 0;
+        float totalMimeFreqScore = 0f;
+        int mimeFreqScoreCount = 0;
+        // Top of this heap has lowest rank.
+        PriorityQueue<Pair<ShareTargetRankingScore, Range<Long>>> recencyMinHeap =
+                new PriorityQueue<>(RECENCY_SCORE_COUNT,
+                        Comparator.comparingLong(p -> p.second.getUpper()));
+        List<ShareTargetRankingScore> scoreList = new ArrayList<>(shareTargets.size());
+        for (ShareTargetPredictor.ShareTarget target : shareTargets) {
+            ShareTargetRankingScore shareTargetScore = new ShareTargetRankingScore();
+            scoreList.add(shareTargetScore);
+            if (target.getEventHistory() == null) {
+                continue;
+            }
+            // Counts frequency
+            List<Range<Long>> timeSlots = target.getEventHistory().getEventIndex(
+                    Event.SHARE_EVENT_TYPES).getActiveTimeSlots();
+            if (!timeSlots.isEmpty()) {
+                for (Range<Long> timeSlot : timeSlots) {
+                    shareTargetScore.incrementFrequencyScore(
+                            getFreqDecayedOnElapsedTime(now - timeSlot.getLower()));
+                }
+                totalFreqScore += shareTargetScore.getFrequencyScore();
+                freqScoreCount++;
+            }
+            // Counts frequency for sharing same mime type
+            List<Range<Long>> timeSlotsOfSameType = target.getEventHistory().getEventIndex(
+                    shareEventType).getActiveTimeSlots();
+            if (!timeSlotsOfSameType.isEmpty()) {
+                for (Range<Long> timeSlot : timeSlotsOfSameType) {
+                    shareTargetScore.incrementMimeFrequencyScore(
+                            getFreqDecayedOnElapsedTime(now - timeSlot.getLower()));
+                }
+                totalMimeFreqScore += shareTargetScore.getMimeFrequencyScore();
+                mimeFreqScoreCount++;
+            }
+            // Records most recent targets
+            Range<Long> mostRecentTimeSlot = target.getEventHistory().getEventIndex(
+                    Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot();
+            if (mostRecentTimeSlot == null) {
+                continue;
+            }
+            if (recencyMinHeap.size() < RECENCY_SCORE_COUNT
+                    || mostRecentTimeSlot.getUpper() > recencyMinHeap.peek().second.getUpper()) {
+                if (recencyMinHeap.size() == RECENCY_SCORE_COUNT) {
+                    recencyMinHeap.poll();
+                }
+                recencyMinHeap.offer(new Pair(shareTargetScore, mostRecentTimeSlot));
+            }
+        }
+        // Calculates recency score
+        while (!recencyMinHeap.isEmpty()) {
+            float recencyScore = RECENCY_INITIAL_BASE_SCORE;
+            if (recencyMinHeap.size() > 1) {
+                recencyScore = RECENCY_INITIAL_BASE_SCORE - RECENCY_SCORE_INITIAL_DECAY
+                        - RECENCY_SCORE_SUBSEQUENT_DECAY * (recencyMinHeap.size() - 2);
+            }
+            recencyMinHeap.poll().first.setRecencyScore(recencyScore);
+        }
+
+        Float avgFreq = freqScoreCount != 0 ? totalFreqScore / freqScoreCount : 0f;
+        Float avgMimeFreq = mimeFreqScoreCount != 0 ? totalMimeFreqScore / mimeFreqScoreCount : 0f;
+        for (int i = 0; i < scoreList.size(); i++) {
+            ShareTargetPredictor.ShareTarget target = shareTargets.get(i);
+            ShareTargetRankingScore targetScore = scoreList.get(i);
+            // Normalizes freq and mimeFreq score
+            targetScore.setFrequencyScore(normalizeFreqScore(
+                    avgFreq.equals(0f) ? 0f : targetScore.getFrequencyScore() / avgFreq));
+            targetScore.setMimeFrequencyScore(normalizeMimeFreqScore(avgMimeFreq.equals(0f) ? 0f
+                    : targetScore.getMimeFrequencyScore() / avgMimeFreq));
+            // Calculates total score
+            targetScore.setTotalScore(
+                    probOR(probOR(targetScore.getRecencyScore(), targetScore.getFrequencyScore()),
+                            targetScore.getMimeFrequencyScore()));
+            target.setScore(targetScore.getTotalScore());
+
+            if (DEBUG) {
+                Slog.d(TAG, String.format(
+                        "SharesheetModel: packageName: %s, className: %s, shortcutId: %s, "
+                                + "recency:%.2f, freq_all:%.2f, freq_mime:%.2f, total:%.2f",
+                        target.getAppTarget().getPackageName(),
+                        target.getAppTarget().getClassName(),
+                        target.getAppTarget().getShortcutInfo() != null
+                                ? target.getAppTarget().getShortcutInfo().getId() : null,
+                        targetScore.getRecencyScore(),
+                        targetScore.getFrequencyScore(),
+                        targetScore.getMimeFrequencyScore(),
+                        targetScore.getTotalScore()));
+            }
+        }
+    }
+
+    /**
+     * Computes ranking score for app sharing. Update {@link ShareTargetPredictor.ShareTargetScore}.
+     */
+    static void computeScoreForAppShare(List<ShareTargetPredictor.ShareTarget> shareTargets,
+            int shareEventType, int targetsLimit, long now, @NonNull DataManager dataManager,
+            @UserIdInt int callingUserId) {
+        computeScore(shareTargets, shareEventType, now);
+        postProcess(shareTargets, targetsLimit, dataManager, callingUserId);
+    }
+
+    private static void postProcess(List<ShareTargetPredictor.ShareTarget> shareTargets,
+            int targetsLimit, @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+        // Populates a map which key is package name and value is list of shareTargets descended
+        // on total score.
+        Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap = new ArrayMap<>();
+        for (ShareTargetPredictor.ShareTarget shareTarget : shareTargets) {
+            String packageName = shareTarget.getAppTarget().getPackageName();
+            shareTargetMap.computeIfAbsent(packageName, key -> new ArrayList<>());
+            List<ShareTargetPredictor.ShareTarget> targetsList = shareTargetMap.get(packageName);
+            int index = 0;
+            while (index < targetsList.size()) {
+                if (shareTarget.getScore() > targetsList.get(index).getScore()) {
+                    break;
+                }
+                index++;
+            }
+            targetsList.add(index, shareTarget);
+        }
+        promoteForegroundApp(shareTargetMap, dataManager, callingUserId);
+        promoteFrequentlyUsedApps(shareTargetMap, targetsLimit, dataManager, callingUserId);
+    }
+
+    /**
+     * Promotes frequently used sharing apps, if recommended apps based on sharing history have not
+     * reached the limit (e.g. user did not share any content in last couple weeks)
+     */
+    private static void promoteFrequentlyUsedApps(
+            Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap, int targetsLimit,
+            @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+        int validPredictionNum = 0;
+        float minValidScore = 1f;
+        for (List<ShareTargetPredictor.ShareTarget> targets : shareTargetMap.values()) {
+            for (ShareTargetPredictor.ShareTarget target : targets) {
+                if (target.getScore() > 0f) {
+                    validPredictionNum++;
+                    minValidScore = Math.min(target.getScore(), minValidScore);
+                }
+            }
+        }
+        // Skips if recommended apps based on sharing history have already reached the limit.
+        if (validPredictionNum >= targetsLimit) {
+            return;
+        }
+        long now = System.currentTimeMillis();
+        Map<String, Integer> appLaunchCountsMap = dataManager.queryAppLaunchCount(
+                callingUserId, now - ONE_MONTH_WINDOW, now, shareTargetMap.keySet());
+        List<Pair<String, Integer>> appLaunchCounts = new ArrayList<>();
+        for (Map.Entry<String, Integer> entry : appLaunchCountsMap.entrySet()) {
+            if (entry.getValue() > 0) {
+                appLaunchCounts.add(new Pair(entry.getKey(), entry.getValue()));
+            }
+        }
+        Collections.sort(appLaunchCounts, (p1, p2) -> -Integer.compare(p1.second, p2.second));
+        for (Pair<String, Integer> entry : appLaunchCounts) {
+            if (!shareTargetMap.containsKey(entry.first)) {
+                continue;
+            }
+            ShareTargetPredictor.ShareTarget target = shareTargetMap.get(entry.first).get(0);
+            if (target.getScore() > 0f) {
+                continue;
+            }
+            minValidScore *= FREQUENTLY_USED_APP_SCORE_DECAY;
+            target.setScore(minValidScore);
+            if (DEBUG) {
+                Slog.d(TAG, String.format(
+                        "SharesheetModel: promoteFrequentUsedApps packageName: %s, className: %s,"
+                                + " total:%.2f",
+                        target.getAppTarget().getPackageName(),
+                        target.getAppTarget().getClassName(),
+                        target.getScore()));
+            }
+            validPredictionNum++;
+            if (validPredictionNum == targetsLimit) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * Promotes the foreground app just prior to source sharing app. Share often occurs between
+     * two apps the user is switching.
+     */
+    private static void promoteForegroundApp(
+            Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap,
+            @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+        String sharingForegroundApp = findSharingForegroundApp(shareTargetMap, dataManager,
+                callingUserId);
+        if (sharingForegroundApp != null) {
+            ShareTargetPredictor.ShareTarget target = shareTargetMap.get(sharingForegroundApp).get(
+                    0);
+            target.setScore(probOR(target.getScore(), FOREGROUND_APP_WEIGHT));
+            if (DEBUG) {
+                Slog.d(TAG, String.format(
+                        "SharesheetModel: promoteForegroundApp packageName: %s, className: %s, "
+                                + "total:%.2f",
+                        target.getAppTarget().getPackageName(),
+                        target.getAppTarget().getClassName(),
+                        target.getScore()));
+            }
+        }
+    }
+
+    /**
+     * Find the foreground app just prior to source sharing app from usageStatsManager. Returns null
+     * if it is not available.
+     */
+    @Nullable
+    private static String findSharingForegroundApp(
+            Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap,
+            @NonNull DataManager dataManager, @UserIdInt int callingUserId) {
+        String sharingForegroundApp = null;
+        long now = System.currentTimeMillis();
+        List<UsageEvents.Event> events = dataManager.queryAppMovingToForegroundEvents(
+                callingUserId, now - FOREGROUND_APP_PROMO_TIME_WINDOW, now);
+        String sourceApp = null;
+        for (int i = events.size() - 1; i >= 0; i--) {
+            String className = events.get(i).getClassName();
+            String packageName = events.get(i).getPackageName();
+            if (packageName == null || (className != null && className.contains(CHOOSER_ACTIVITY))
+                    || packageName.contains(CHOOSER_ACTIVITY)) {
+                continue;
+            }
+            if (sourceApp == null) {
+                sourceApp = packageName;
+            } else if (!packageName.equals(sourceApp) && shareTargetMap.containsKey(packageName)) {
+                sharingForegroundApp = packageName;
+                break;
+            }
+        }
+        return sharingForegroundApp;
+    }
+
+    /**
+     * Probabilistic OR (also known as the algebraic sum). If a <= 1 and b <= 1, the result will be
+     * <= 1.0.
+     */
+    private static float probOR(float a, float b) {
+        return 1f - (1f - a) * (1f - b);
+    }
+
+    /** Counts frequency of share targets. Decays frequency for old shares. */
+    private static float getFreqDecayedOnElapsedTime(long elapsedTimeMillis) {
+        Duration duration = Duration.ofMillis(elapsedTimeMillis);
+        if (duration.compareTo(Duration.ofDays(1)) <= 0) {
+            return 1.0f;
+        } else if (duration.compareTo(Duration.ofDays(3)) <= 0) {
+            return 0.9f;
+        } else if (duration.compareTo(Duration.ofDays(7)) <= 0) {
+            return 0.8f;
+        } else if (duration.compareTo(Duration.ofDays(14)) <= 0) {
+            return 0.7f;
+        } else {
+            return 0.6f;
+        }
+    }
+
+    /** Normalizes frequency score. */
+    private static float normalizeFreqScore(double freqRatio) {
+        if (freqRatio >= 2.5) {
+            return 0.2f;
+        } else if (freqRatio >= 1.5) {
+            return 0.15f;
+        } else if (freqRatio >= 1.0) {
+            return 0.1f;
+        } else if (freqRatio >= 0.75) {
+            return 0.05f;
+        } else {
+            return 0f;
+        }
+    }
+
+    /** Normalizes mimetype-specific frequency score. */
+    private static float normalizeMimeFreqScore(double freqRatio) {
+        if (freqRatio >= 2.0) {
+            return 0.2f;
+        } else if (freqRatio >= 1.2) {
+            return 0.15f;
+        } else if (freqRatio > 0.0) {
+            return 0.1f;
+        } else {
+            return 0f;
+        }
+    }
+
+    private static class ShareTargetRankingScore {
+
+        private float mRecencyScore = 0f;
+        private float mFrequencyScore = 0f;
+        private float mMimeFrequencyScore = 0f;
+        private float mTotalScore = 0f;
+
+        float getTotalScore() {
+            return mTotalScore;
+        }
+
+        void setTotalScore(float totalScore) {
+            mTotalScore = totalScore;
+        }
+
+        float getRecencyScore() {
+            return mRecencyScore;
+        }
+
+        void setRecencyScore(float recencyScore) {
+            mRecencyScore = recencyScore;
+        }
+
+        float getFrequencyScore() {
+            return mFrequencyScore;
+        }
+
+        void setFrequencyScore(float frequencyScore) {
+            mFrequencyScore = frequencyScore;
+        }
+
+        void incrementFrequencyScore(float incremental) {
+            mFrequencyScore += incremental;
+        }
+
+        float getMimeFrequencyScore() {
+            return mMimeFrequencyScore;
+        }
+
+        void setMimeFrequencyScore(float mimeFrequencyScore) {
+            mMimeFrequencyScore = mimeFrequencyScore;
+        }
+
+        void incrementMimeFrequencyScore(float incremental) {
+            mMimeFrequencyScore += incremental;
+        }
+    }
+}
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index acdb6814..138f982 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
 import static android.app.AppOpsManager.OP_INTERACT_ACROSS_PROFILES;
 import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
 import static android.content.Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND;
@@ -104,6 +105,7 @@
     private final CrossProfileAppsServiceImpl mCrossProfileAppsServiceImpl =
             new CrossProfileAppsServiceImpl(mContext, mInjector);
     private final Map<UserHandle, Set<Intent>> mSentUserBroadcasts = new HashMap<>();
+    private final Map<Integer, List<ApplicationInfo>> installedApplications = new HashMap<>();
 
     @Mock private PackageManagerInternal mPackageManagerInternal;
     @Mock private IPackageManager mIPackageManager;
@@ -112,12 +114,18 @@
     @Before
     public void initializeMocks() throws Exception {
         MockitoAnnotations.initMocks(this);
+        initializeInstalledApplicationsMock();
         mockCrossProfileAppInstalledAndEnabledOnEachProfile();
         mockCrossProfileAppRequestsInteractAcrossProfiles();
         mockCrossProfileAppRegistersBroadcastReceiver();
         mockCrossProfileAppWhitelisted();
     }
 
+    private void initializeInstalledApplicationsMock() {
+        when(mPackageManagerInternal.getInstalledApplications(anyInt(), anyInt(), eq(CALLING_UID)))
+                .thenAnswer(invocation -> installedApplications.get(invocation.getArgument(1)));
+    }
+
     private void mockCrossProfileAppInstalledAndEnabledOnEachProfile() {
         // They are enabled by default, so we simply have to ensure that a package info with an
         // application info is returned.
@@ -138,11 +146,14 @@
         when(mPackageManagerInternal.getPackage(uid))
                 .thenReturn(((ParsedPackage) PackageImpl.forTesting(CROSS_PROFILE_APP_PACKAGE_NAME)
                         .hideAsParsed()).hideAsFinal());
+        installedApplications.putIfAbsent(userId, new ArrayList<>());
+        installedApplications.get(userId).add(packageInfo.applicationInfo);
     }
 
     private PackageInfo buildTestPackageInfo() {
         PackageInfo packageInfo = new PackageInfo();
         packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.packageName = CROSS_PROFILE_APP_PACKAGE_NAME;
         return packageInfo;
     }
 
@@ -451,6 +462,13 @@
                 .isTrue();
     }
 
+    @Test
+    public void clearInteractAcrossProfilesAppOps() {
+        explicitlySetInteractAcrossProfilesAppOp(MODE_ALLOWED);
+        mCrossProfileAppsServiceImpl.clearInteractAcrossProfilesAppOps();
+        assertThat(getCrossProfileAppOp()).isEqualTo(MODE_DEFAULT);
+    }
+
     private void explicitlySetInteractAcrossProfilesAppOp(@Mode int mode) {
         explicitlySetInteractAcrossProfilesAppOp(PERSONAL_PROFILE_UID, mode);
     }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 1212f20..109c119 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -15,218 +15,227 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.servicestests">
+     package="com.android.frameworks.servicestests">
 
-    <uses-permission android:name="android.permission.READ_LOGS" />
-    <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
-    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
-    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
-    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
-    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
-    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
-    <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
-    <uses-permission android:name="android.permission.REORDER_TASKS" />
-    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
-    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
-    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
-    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
-    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
-    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
-    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
-    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
-    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
-    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
-    <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
-    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+    <uses-permission android:name="android.permission.READ_LOGS"/>
+    <uses-permission android:name="android.permission.ACCESS_VR_MANAGER"/>
+    <uses-permission android:name="android.permission.ACCOUNT_MANAGER"/>
+    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.BROADCAST_STICKY"/>
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS"/>
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.REAL_GET_TASKS"/>
+    <uses-permission android:name="android.permission.GET_DETAILED_TASKS"/>
+    <uses-permission android:name="android.permission.REORDER_TASKS"/>
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+    <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.MANAGE_USERS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS"/>
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"/>
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT"/>
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"/>
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
+    <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
+    <uses-permission android:name="android.permission.DELETE_PACKAGES"/>
+    <uses-permission android:name="android.permission.GET_APP_OPS_STATS"/>
+    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"/>
     <uses-permission android:name="android.permission.MANAGE_APP_OPS_MODES"/>
-    <uses-permission android:name="android.permission.DEVICE_POWER" />
-    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
-    <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
-    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
-    <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
-    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
-    <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <uses-permission android:name="android.permission.STORAGE_INTERNAL" />
-    <uses-permission android:name="android.permission.WATCH_APPOPS" />
+    <uses-permission android:name="android.permission.DEVICE_POWER"/>
+    <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"/>
+    <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
+    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
+    <uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
+    <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"/>
+    <uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.STORAGE_INTERNAL"/>
+    <uses-permission android:name="android.permission.WATCH_APPOPS"/>
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.SUSPEND_APPS"/>
-    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
-    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
+    <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
+    <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
     <uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
-    <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
-    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
-    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS"/>
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
+    <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.HARDWARE_TEST"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
-    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
-    <uses-permission android:name="android.permission.DUMP" />
+    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
+    <uses-permission android:name="android.permission.DUMP"/>
     <uses-permission android:name="android.permission.READ_DREAM_STATE"/>
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
-          android:targetSdkVersion="26"/>
+         android:targetSdkVersion="26"/>
 
     <application android:testOnly="true">
-        <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner"/>
 
         <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
-            android:exported="false">
+             android:exported="false">
           <intent-filter>
-            <action android:name="android.accounts.AccountAuthenticator" />
+            <action android:name="android.accounts.AccountAuthenticator"/>
           </intent-filter>
           <meta-data android:name="android.accounts.AccountAuthenticator"
-              android:resource="@xml/test_account_type1_authenticator" />
+               android:resource="@xml/test_account_type1_authenticator"/>
         </service>
 
         <service android:name="com.android.server.accounts.TestAccountType2AuthenticatorService"
-            android:exported="false">
+             android:exported="false">
           <intent-filter>
-            <action android:name="android.accounts.AccountAuthenticator" />
+            <action android:name="android.accounts.AccountAuthenticator"/>
           </intent-filter>
           <meta-data android:name="android.accounts.AccountAuthenticator"
-              android:resource="@xml/test_account_type2_authenticator" />
+               android:resource="@xml/test_account_type2_authenticator"/>
         </service>
 
         <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
+             android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
-                       android:resource="@xml/device_admin_sample" />
+                 android:resource="@xml/device_admin_sample"/>
             <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
-            android:permission="android.permission.BIND_DEVICE_ADMIN">
+             android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
-                android:resource="@xml/device_admin_sample" />
+                 android:resource="@xml/device_admin_sample"/>
             <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"
-            android:permission="android.permission.BIND_DEVICE_ADMIN">
+             android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
-                android:resource="@xml/device_admin_sample" />
+                 android:resource="@xml/device_admin_sample"/>
             <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"
-            android:permission="android.permission.BIND_DEVICE_ADMIN">
+             android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
-                android:resource="@xml/device_admin_sample" />
+                 android:resource="@xml/device_admin_sample"/>
             <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$AdminNoPerm">
             <meta-data android:name="android.app.device_admin"
-                android:resource="@xml/device_admin_sample" />
+                 android:resource="@xml/device_admin_sample"/>
             <intent-filter>
-                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
             </intent-filter>
         </receiver>
 
         <service android:name="com.android.server.job.MockPriorityJobService"
-                 android:permission="android.permission.BIND_JOB_SERVICE" />
+             android:permission="android.permission.BIND_JOB_SERVICE"/>
 
-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity" />
-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
-        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
+        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity"/>
+        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2"/>
+        <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3"/>
 
         <activity android:name="com.android.server.pm.ShortcutTestActivity"
-                 android:enabled="true" android:exported="true" />
+             android:enabled="true"
+             android:exported="true"/>
 
         <activity android:name="com.android.server.pm.SuspendedDetailsActivity"
-                  android:enabled="true"
-                  android:permission="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS">
+             android:enabled="true"
+             android:permission="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS">
             <intent-filter>
-                <action android:name="android.intent.action.SHOW_SUSPENDED_APP_DETAILS" />
-                <category android:name="android.intent.category.DEFAULT" />
+                <action android:name="android.intent.action.SHOW_SUSPENDED_APP_DETAILS"/>
+                <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
 
-        <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
-        <activity android:name="com.android.server.adb.AdbDebuggingManagerTestActivity" />
+        <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity"/>
+        <activity android:name="com.android.server.adb.AdbDebuggingManagerTestActivity"/>
 
         <activity-alias android:name="a.ShortcutEnabled"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="true">
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="true"
+             android:exported="true">
         </activity-alias>
         <activity-alias android:name="a.ShortcutDisabled"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="false" android:exported="true">
-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="false"
+             android:exported="true">
+            <meta-data android:name="android.app.shortcuts"
+                 android:resource="@xml/shortcut_5"/>
         </activity-alias>
         <activity-alias android:name="a.ShortcutUnexported"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="false">
-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_5"/>
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="true"
+             android:exported="false">
+            <meta-data android:name="android.app.shortcuts"
+                 android:resource="@xml/shortcut_5"/>
         </activity-alias>
         <activity-alias android:name="a.Shortcut1"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="true">
-            <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_1"/>
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="true"
+             android:exported="true">
+            <meta-data android:name="android.app.shortcuts"
+                 android:resource="@xml/shortcut_1"/>
         </activity-alias>
         <activity-alias android:name="a.ShortcutConfigActivity"
-                        android:targetActivity="com.android.server.pm.ShortcutTestActivity">
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity">
             <intent-filter>
-                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+                <action android:name="android.intent.action.CREATE_SHORTCUT"/>
             </intent-filter>
         </activity-alias>
 
         <activity-alias android:name="a.DisabledMain"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="false" android:exported="true">
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="false"
+             android:exported="true">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity-alias>
 
         <activity-alias android:name="a.UnexportedMain"
-            android:targetActivity="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="false">
+             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
+             android:enabled="true"
+             android:exported="false">
             <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity-alias>
 
         <receiver android:name="com.android.server.appwidget.DummyAppWidget">
             <intent-filter>
-                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
+                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
             </intent-filter>
             <meta-data android:name="android.appwidget.provider"
-              android:resource="@xml/dummy_appwidget_info" />
+                 android:resource="@xml/dummy_appwidget_info"/>
         </receiver>
     </application>
 
-    <instrumentation
-        android:name="androidx.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.frameworks.servicestests"
-        android:label="Frameworks Services Tests" />
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+         android:targetPackage="com.android.frameworks.servicestests"
+         android:label="Frameworks Services Tests"/>
 </manifest>
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 3ad9054..d292526 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -64,10 +64,13 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.AdditionalMatchers;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Random;
+
 @SmallTest
 public class BiometricServiceTest {
 
@@ -347,9 +350,19 @@
     }
 
     @Test
-    public void testAuthenticate_happyPathWithoutConfirmation() throws Exception {
+    public void testAuthenticate_happyPathWithoutConfirmation_strongBiometric() throws Exception {
         setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_STRONG);
+        testAuthenticate_happyPathWithoutConfirmation(true /* isStrongBiometric */);
+    }
 
+    @Test
+    public void testAuthenticate_happyPathWithoutConfirmation_weakBiometric() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FINGERPRINT, Authenticators.BIOMETRIC_WEAK);
+        testAuthenticate_happyPathWithoutConfirmation(false /* isStrongBiometric */);
+    }
+
+    private void testAuthenticate_happyPathWithoutConfirmation(boolean isStrongBiometric)
+            throws Exception {
         // Start testing the happy path
         invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
                 null /* authenticators */);
@@ -397,9 +410,11 @@
                 anyLong() /* sessionId */);
 
         // Hardware authenticated
+        final byte[] HAT = generateRandomHAT();
         mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
                 false /* requireConfirmation */,
-                new byte[69] /* HAT */);
+                HAT,
+                isStrongBiometric /* isStrongBiometric */);
         waitForIdle();
         // Waiting for SystemUI to send dismissed callback
         assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -413,7 +428,11 @@
                 null /* credentialAttestation */);
         waitForIdle();
         // HAT sent to keystore
-        verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+        if (isStrongBiometric) {
+            verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+        } else {
+            verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+        }
         // Send onAuthenticated to client
         verify(mReceiver1).onAuthenticationSucceeded(
                 BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
@@ -447,16 +466,29 @@
     }
 
     @Test
-    public void testAuthenticate_happyPathWithConfirmation() throws Exception {
+    public void testAuthenticate_happyPathWithConfirmation_strongBiometric() throws Exception {
         setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_STRONG);
+        testAuthenticate_happyPathWithConfirmation(true /* isStrongBiometric */);
+    }
+
+    @Test
+    public void testAuthenticate_happyPathWithConfirmation_weakBiometric() throws Exception {
+        setupAuthForOnly(BiometricAuthenticator.TYPE_FACE, Authenticators.BIOMETRIC_WEAK);
+        testAuthenticate_happyPathWithConfirmation(false /* isStrongBiometric */);
+    }
+
+    private void testAuthenticate_happyPathWithConfirmation(boolean isStrongBiometric)
+            throws Exception {
         invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
                 true /* requireConfirmation */, null /* authenticators */);
 
         // Test authentication succeeded goes to PENDING_CONFIRMATION and that the HAT is not
         // sent to KeyStore yet
+        final byte[] HAT = generateRandomHAT();
         mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
                 true /* requireConfirmation */,
-                new byte[69] /* HAT */);
+                HAT,
+                isStrongBiometric /* isStrongBiometric */);
         waitForIdle();
         // Waiting for SystemUI to send confirmation callback
         assertEquals(mBiometricService.mCurrentAuthSession.mState,
@@ -468,7 +500,11 @@
                 BiometricPrompt.DISMISSED_REASON_BIOMETRIC_CONFIRMED,
                 null /* credentialAttestation */);
         waitForIdle();
-        verify(mBiometricService.mKeyStore).addAuthToken(any(byte[].class));
+        if (isStrongBiometric) {
+            verify(mBiometricService.mKeyStore).addAuthToken(AdditionalMatchers.aryEq(HAT));
+        } else {
+            verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
+        }
         verify(mReceiver1).onAuthenticationSucceeded(
                 BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC);
     }
@@ -909,7 +945,8 @@
 
         mBiometricService.mInternalReceiver.onAuthenticationSucceeded(
                 true /* requireConfirmation */,
-                new byte[69] /* HAT */);
+                new byte[69] /* HAT */,
+                true /* isStrongBiometric */);
         mBiometricService.mInternalReceiver.onDialogDismissed(
                 BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */);
         waitForIdle();
@@ -927,6 +964,7 @@
                 eq(BiometricAuthenticator.TYPE_FACE),
                 eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
                 eq(0 /* vendorCode */));
+        verify(mBiometricService.mKeyStore, never()).addAuthToken(any(byte[].class));
         assertNull(mBiometricService.mCurrentAuthSession);
     }
 
@@ -1238,20 +1276,6 @@
                 mFingerprintAuthenticator);
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void testRegistrationWithUnsupportedStrength_throwsIllegalStateException()
-            throws Exception {
-        mBiometricService = new BiometricService(mContext, mInjector);
-        mBiometricService.onStart();
-
-        // Only STRONG and WEAK are supported. Let's enforce that CONVENIENCE cannot be
-        // registered. If there is a compelling reason, we can remove this constraint.
-        mBiometricService.mImpl.registerAuthenticator(
-                0 /* id */, 2 /* modality */,
-                Authenticators.BIOMETRIC_CONVENIENCE /* strength */,
-                mFingerprintAuthenticator);
-    }
-
     @Test(expected = IllegalArgumentException.class)
     public void testRegistrationWithNullAuthenticator_throwsIllegalArgumentException()
             throws Exception {
@@ -1508,4 +1532,13 @@
     private static void waitForIdle() {
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
+
+    private byte[] generateRandomHAT() {
+        byte[] HAT = new byte[69];
+        Random random = new Random();
+        random.nextBytes(HAT);
+        return HAT;
+    }
+
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7c6ac17..baf551e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3205,6 +3205,7 @@
         when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                 .thenReturn(true);
         setUserSetupCompleteForUser(false, UserHandle.USER_SYSTEM);
+        when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
     }
@@ -3246,6 +3247,7 @@
         when(getServices().userManager.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM, true))
                 .thenReturn(true);
         setUserSetupCompleteForUser(true, UserHandle.USER_SYSTEM);
+        when(getServices().userManager.getProfileParent(UserHandle.USER_SYSTEM)).thenReturn(null);
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
     }
@@ -3617,14 +3619,14 @@
 
         when(getServices().ipackageManager.hasSystemFeature(PackageManager.FEATURE_MANAGED_USERS, 0))
                 .thenReturn(true);
-        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(true);
+        when(getServices().userManagerForMock.isSplitSystemUser()).thenReturn(false);
         when(getServices().userManager.getProfileParent(DpmMockContext.CALLER_USER_HANDLE))
             .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
         when(getServices().userManager.canAddMoreManagedProfiles(DpmMockContext.CALLER_USER_HANDLE,
                 true)).thenReturn(true);
         setUserSetupCompleteForUser(false, DpmMockContext.CALLER_USER_HANDLE);
 
-        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
     }
 
     public void testIsProvisioningAllowed_provisionManagedProfileWithDeviceOwner_primaryUser()
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index 7934d33..03d9ad5 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -21,15 +21,16 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.Context;
 import android.content.LocusId;
@@ -50,6 +51,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.function.Predicate;
@@ -58,7 +60,8 @@
 public final class UsageStatsQueryHelperTest {
 
     private static final int USER_ID_PRIMARY = 0;
-    private static final String PKG_NAME = "pkg";
+    private static final String PKG_NAME_1 = "pkg_1";
+    private static final String PKG_NAME_2 = "pkg_2";
     private static final String ACTIVITY_NAME = "TestActivity";
     private static final String SHORTCUT_ID = "abc";
     private static final LocusId LOCUS_ID_1 = new LocusId("locus_1");
@@ -80,7 +83,7 @@
         File testDir = new File(ctx.getCacheDir(), "testdir");
         ScheduledExecutorService scheduledExecutorService = new MockScheduledExecutorService();
 
-        mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false,
+        mPackageData = new TestPackageData(PKG_NAME_1, USER_ID_PRIMARY, pkg -> false, pkg -> false,
                 scheduledExecutorService, testDir);
         mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder()
                 .setShortcutId(SHORTCUT_ID)
@@ -173,10 +176,72 @@
         assertEquals(createInAppConversationEvent(130_000L, 30), events.get(2));
     }
 
+    @Test
+    public void testQueryAppMovingToForegroundEvents() {
+        addUsageEvents(
+                createShortcutInvocationEvent(100_000L),
+                createActivityResumedEvent(110_000L),
+                createActivityStoppedEvent(120_000L),
+                createActivityResumedEvent(130_000L));
+
+        List<UsageEvents.Event> events = mHelper.queryAppMovingToForegroundEvents(USER_ID_PRIMARY,
+                90_000L,
+                200_000L);
+
+        assertEquals(2, events.size());
+        assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(0).getEventType());
+        assertEquals(110_000L, events.get(0).getTimeStamp());
+        assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(1).getEventType());
+        assertEquals(130_000L, events.get(1).getTimeStamp());
+    }
+
+    @Test
+    public void testQueryAppLaunchCount() {
+
+        UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2);
+        UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3);
+        UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1);
+        when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(),
+                anyLong(), anyBoolean())).thenReturn(
+                List.of(packageStats1, packageStats2, packageStats3));
+
+        Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L,
+                200_000L, Set.of(PKG_NAME_1, PKG_NAME_2));
+
+        assertEquals(2, appLaunchCounts.size());
+        assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1));
+        assertEquals(1, (long) appLaunchCounts.get(PKG_NAME_2));
+    }
+
+    @Test
+    public void testQueryAppLaunchCount_packageNameFiltered() {
+
+        UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2);
+        UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3);
+        UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1);
+        when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(),
+                anyLong(), anyBoolean())).thenReturn(
+                List.of(packageStats1, packageStats2, packageStats3));
+
+        Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L,
+                200_000L,
+                Set.of(PKG_NAME_1));
+
+        assertEquals(1, appLaunchCounts.size());
+        assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1));
+    }
+
     private void addUsageEvents(UsageEvents.Event... events) {
         UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
         when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
-                eq(UsageEvents.SHOW_ALL_EVENT_DATA))).thenReturn(usageEvents);
+                anyInt())).thenReturn(usageEvents);
+    }
+
+    private static UsageStats createUsageStats(String packageName, int launchCount) {
+        UsageStats packageStats = new UsageStats();
+        packageStats.mPackageName = packageName;
+        packageStats.mAppLaunchCount = launchCount;
+        return packageStats;
     }
 
     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
@@ -203,9 +268,15 @@
         return e;
     }
 
+    private static UsageEvents.Event createActivityResumedEvent(long timestamp) {
+        UsageEvents.Event e = createUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, timestamp);
+        e.mClass = ACTIVITY_NAME;
+        return e;
+    }
+
     private static UsageEvents.Event createUsageEvent(int eventType, long timestamp) {
         UsageEvents.Event e = new UsageEvents.Event(eventType, timestamp);
-        e.mPackage = PKG_NAME;
+        e.mPackage = PKG_NAME_1;
         return e;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
index c6cd347..1480627 100644
--- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java
@@ -127,6 +127,9 @@
         when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
         when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
         when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3);
         when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
         when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
         when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
@@ -183,6 +186,12 @@
         when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
         when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
         when(mEventHistory6.getEventIndex(anySet())).thenReturn(mEventIndex6);
+        when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anyInt())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anyInt())).thenReturn(mEventIndex5);
+        when(mEventHistory6.getEventIndex(anyInt())).thenReturn(mEventIndex6);
         when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
         when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
         when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
@@ -220,19 +229,19 @@
     @Test
     public void testSortTargets() {
         AppTarget appTarget1 = new AppTarget.Builder(
-                    new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+                new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
                 .setClassName(CLASS_1)
                 .build();
         AppTarget appTarget2 = new AppTarget.Builder(
-                    new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+                new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
                 .setClassName(CLASS_2)
                 .build();
         AppTarget appTarget3 = new AppTarget.Builder(
-                    new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
                 .setClassName(CLASS_1)
                 .build();
         AppTarget appTarget4 = new AppTarget.Builder(
-                    new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
                 .setClassName(CLASS_2)
                 .build();
         AppTarget appTarget5 = new AppTarget.Builder(
@@ -251,6 +260,10 @@
         when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
         when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
         when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anyInt())).thenReturn(mEventIndex4);
         when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L));
         when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L));
         when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L));
@@ -265,14 +278,14 @@
                 appTarget4, appTarget3, appTarget2, appTarget1, appTarget5);
     }
 
-    private ShareShortcutInfo buildShareShortcut(
+    private static ShareShortcutInfo buildShareShortcut(
             String packageName, String className, String shortcutId) {
         ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId);
         ComponentName componentName = new ComponentName(packageName, className);
         return new ShareShortcutInfo(shortcutInfo, componentName);
     }
 
-    private ShortcutInfo buildShortcut(String packageName, String shortcutId) {
+    private static ShortcutInfo buildShortcut(String packageName, String shortcutId) {
         Context mockContext = mock(Context.class);
         when(mockContext.getPackageName()).thenReturn(packageName);
         when(mockContext.getUserId()).thenReturn(USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
new file mode 100644
index 0000000..9d96d6b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.people.prediction;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anySet;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.prediction.AppTarget;
+import android.app.prediction.AppTargetId;
+import android.app.usage.UsageEvents;
+import android.os.UserHandle;
+import android.util.Range;
+
+import com.android.server.people.data.DataManager;
+import com.android.server.people.data.Event;
+import com.android.server.people.data.EventHistory;
+import com.android.server.people.data.EventIndex;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public final class SharesheetModelScorerTest {
+
+    private static final int USER_ID = 0;
+    private static final String PACKAGE_1 = "pkg1";
+    private static final String PACKAGE_2 = "pkg2";
+    private static final String PACKAGE_3 = "pkg3";
+    private static final String CLASS_1 = "cls1";
+    private static final String CLASS_2 = "cls2";
+    private static final double DELTA = 1e-6;
+    private static final long NOW = System.currentTimeMillis();
+    private static final Range<Long> WITHIN_ONE_DAY = new Range(
+            NOW - Duration.ofHours(23).toMillis(),
+            NOW - Duration.ofHours(22).toMillis());
+    private static final Range<Long> TWO_DAYS_AGO = new Range(
+            NOW - Duration.ofHours(50).toMillis(),
+            NOW - Duration.ofHours(49).toMillis());
+    private static final Range<Long> FIVE_DAYS_AGO = new Range(
+            NOW - Duration.ofDays(6).toMillis(),
+            NOW - Duration.ofDays(5).toMillis());
+    private static final Range<Long> EIGHT_DAYS_AGO = new Range(
+            NOW - Duration.ofDays(9).toMillis(),
+            NOW - Duration.ofDays(8).toMillis());
+    private static final Range<Long> TWELVE_DAYS_AGO = new Range(
+            NOW - Duration.ofDays(13).toMillis(),
+            NOW - Duration.ofDays(12).toMillis());
+    private static final Range<Long> TWENTY_DAYS_AGO = new Range(
+            NOW - Duration.ofDays(21).toMillis(),
+            NOW - Duration.ofDays(20).toMillis());
+    private static final Range<Long> FOUR_WEEKS_AGO = new Range(
+            NOW - Duration.ofDays(29).toMillis(),
+            NOW - Duration.ofDays(28).toMillis());
+
+    @Mock
+    private DataManager mDataManager;
+    @Mock
+    private EventHistory mEventHistory1;
+    @Mock
+    private EventHistory mEventHistory2;
+    @Mock
+    private EventHistory mEventHistory3;
+    @Mock
+    private EventHistory mEventHistory4;
+    @Mock
+    private EventHistory mEventHistory5;
+    @Mock
+    private EventIndex mEventIndex1;
+    @Mock
+    private EventIndex mEventIndex2;
+    @Mock
+    private EventIndex mEventIndex3;
+    @Mock
+    private EventIndex mEventIndex4;
+    @Mock
+    private EventIndex mEventIndex5;
+    @Mock
+    private EventIndex mEventIndex6;
+    @Mock
+    private EventIndex mEventIndex7;
+    @Mock
+    private EventIndex mEventIndex8;
+    @Mock
+    private EventIndex mEventIndex9;
+    @Mock
+    private EventIndex mEventIndex10;
+
+    private ShareTargetPredictor.ShareTarget mShareTarget1;
+    private ShareTargetPredictor.ShareTarget mShareTarget2;
+    private ShareTargetPredictor.ShareTarget mShareTarget3;
+    private ShareTargetPredictor.ShareTarget mShareTarget4;
+    private ShareTargetPredictor.ShareTarget mShareTarget5;
+    private ShareTargetPredictor.ShareTarget mShareTarget6;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mShareTarget1 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(
+                        new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID))
+                        .setClassName(CLASS_1).build(),
+                mEventHistory1, null);
+        mShareTarget2 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(new AppTargetId("cls2#pkg1"), PACKAGE_1,
+                        UserHandle.of(USER_ID)).setClassName(CLASS_2).build(),
+                mEventHistory2, null);
+        mShareTarget3 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(
+                        new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                        .setClassName(CLASS_1).build(),
+                mEventHistory3, null);
+        mShareTarget4 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(
+                        new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID))
+                        .setClassName(CLASS_2).build(),
+                mEventHistory4, null);
+        mShareTarget5 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(
+                        new AppTargetId("cls1#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+                        .setClassName(CLASS_1).build(),
+                mEventHistory5, null);
+        mShareTarget6 = new ShareTargetPredictor.ShareTarget(
+                new AppTarget.Builder(
+                        new AppTargetId("cls2#pkg3"), PACKAGE_3, UserHandle.of(USER_ID))
+                        .setClassName(CLASS_2).build(),
+                null, null);
+    }
+
+    @Test
+    public void testComputeScore() {
+        // Frequency and recency
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+
+        when(mEventIndex1.getActiveTimeSlots()).thenReturn(
+                List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO));
+        when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+        when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO));
+        when(mEventIndex4.getActiveTimeSlots()).thenReturn(
+                List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO));
+        when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of());
+
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+        when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+        when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+
+        // Frequency of the same mime type
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+
+        when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO));
+        when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+        when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of());
+        when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO));
+        when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of());
+
+        SharesheetModelScorer.computeScore(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT,
+                NOW);
+
+        // Verification
+        assertEquals(0.514f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0.475125f, mShareTarget2.getScore(), DELTA);
+        assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+        assertEquals(0.4411f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    @Test
+    public void testComputeScoreForAppShare() {
+        // Frequency and recency
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+
+        when(mEventIndex1.getActiveTimeSlots()).thenReturn(
+                List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO));
+        when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+        when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO));
+        when(mEventIndex4.getActiveTimeSlots()).thenReturn(
+                List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO));
+        when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of());
+
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+        when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+        when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+
+        // Frequency of the same mime type
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+
+        when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO));
+        when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO));
+        when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of());
+        when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO));
+        when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of());
+
+        SharesheetModelScorer.computeScoreForAppShare(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+        // Verification
+        assertEquals(0.514f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0.475125f, mShareTarget2.getScore(), DELTA);
+        assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+        assertEquals(0.4411f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    @Test
+    public void testComputeScoreForAppShare_promoteFrequentlyUsedApps() {
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+        when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet()))
+                .thenReturn(
+                        Map.of(PACKAGE_1, 1,
+                                PACKAGE_2, 2,
+                                PACKAGE_3, 3));
+
+        SharesheetModelScorer.computeScoreForAppShare(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+        verify(mDataManager, times(1)).queryAppLaunchCount(anyInt(), anyLong(), anyLong(),
+                anySet());
+        assertEquals(0.9f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0.81f, mShareTarget3.getScore(), DELTA);
+        assertEquals(0.729f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0f, mShareTarget2.getScore(), DELTA);
+        assertEquals(0f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    @Test
+    public void testComputeScoreForAppShare_skipPromoteFrequentlyUsedAppsWhenReachesLimit() {
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+        when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY);
+        when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO);
+        when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO);
+        when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO);
+        when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null);
+        when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet()))
+                .thenReturn(
+                        Map.of(PACKAGE_1, 1,
+                                PACKAGE_2, 2,
+                                PACKAGE_3, 3));
+
+        SharesheetModelScorer.computeScoreForAppShare(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT, 4, NOW, mDataManager, USER_ID);
+
+        verify(mDataManager, never()).queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet());
+        assertEquals(0.4f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0.35f, mShareTarget2.getScore(), DELTA);
+        assertEquals(0.33f, mShareTarget3.getScore(), DELTA);
+        assertEquals(0.31f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    @Test
+    public void testComputeScoreForAppShare_promoteForegroundApp() {
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+        when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+                anyLong())).thenReturn(
+                List.of(createUsageEvent(PACKAGE_2),
+                        createUsageEvent(PACKAGE_3),
+                        createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY),
+                        createUsageEvent(PACKAGE_3),
+                        createUsageEvent(PACKAGE_3))
+        );
+
+        SharesheetModelScorer.computeScoreForAppShare(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+        verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+                anyLong());
+        assertEquals(0f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0f, mShareTarget2.getScore(), DELTA);
+        assertEquals(SharesheetModelScorer.FOREGROUND_APP_WEIGHT, mShareTarget3.getScore(), DELTA);
+        assertEquals(0f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    @Test
+    public void testComputeScoreForAppShare_skipPromoteForegroundAppWhenNoValidForegroundApp() {
+        when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1);
+        when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2);
+        when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3);
+        when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4);
+        when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5);
+        when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6);
+        when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7);
+        when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8);
+        when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9);
+        when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10);
+        when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+                anyLong())).thenReturn(
+                List.of(createUsageEvent(PACKAGE_3),
+                        createUsageEvent(PACKAGE_3),
+                        createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY),
+                        createUsageEvent(PACKAGE_3),
+                        createUsageEvent(PACKAGE_3))
+        );
+
+        SharesheetModelScorer.computeScoreForAppShare(
+                List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5,
+                        mShareTarget6),
+                Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID);
+
+        verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(),
+                anyLong());
+        assertEquals(0f, mShareTarget1.getScore(), DELTA);
+        assertEquals(0f, mShareTarget2.getScore(), DELTA);
+        assertEquals(0f, mShareTarget3.getScore(), DELTA);
+        assertEquals(0f, mShareTarget4.getScore(), DELTA);
+        assertEquals(0f, mShareTarget5.getScore(), DELTA);
+        assertEquals(0f, mShareTarget6.getScore(), DELTA);
+    }
+
+    private static UsageEvents.Event createUsageEvent(String packageName) {
+        UsageEvents.Event e = new UsageEvents.Event();
+        e.mPackage = packageName;
+        return e;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 40ada2a..db1bbab 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -43,6 +43,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.frameworks.servicestests.R;
+import com.android.server.pm.parsing.PackageParser2;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -63,6 +64,7 @@
     private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777};
     private ApexManager mApexManager;
     private Context mContext;
+    private PackageParser2 mPackageParser2;
 
     private IApexService mApexService = mock(IApexService.class);
 
@@ -70,11 +72,14 @@
     public void setUp() throws RemoteException {
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mApexManager = new ApexManager.ApexManagerImpl(mApexService);
+        mPackageParser2 = new PackageParser2(null, false, null, null, null);
     }
 
     @Test
     public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
         final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                 ApexManager.MATCH_ACTIVE_PACKAGE);
 
@@ -90,6 +95,8 @@
     @Test
     public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
         PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG,
                 ApexManager.MATCH_FACTORY_PACKAGE);
 
@@ -105,6 +112,8 @@
     @Test
     public void testGetPackageInfo_setFlagsNone() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull();
     }
@@ -112,6 +121,8 @@
     @Test
     public void testGetActivePackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getActivePackages()).isNotEmpty();
     }
@@ -119,6 +130,8 @@
     @Test
     public void testGetActivePackages_noneActivePackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getActivePackages()).isEmpty();
     }
@@ -126,6 +139,8 @@
     @Test
     public void testGetFactoryPackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getFactoryPackages()).isNotEmpty();
     }
@@ -133,6 +148,8 @@
     @Test
     public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getFactoryPackages()).isEmpty();
     }
@@ -140,6 +157,8 @@
     @Test
     public void testGetInactivePackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getInactivePackages()).isNotEmpty();
     }
@@ -147,6 +166,8 @@
     @Test
     public void testGetInactivePackages_noneInactivePackages() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.getInactivePackages()).isEmpty();
     }
@@ -154,6 +175,8 @@
     @Test
     public void testIsApexPackage() throws RemoteException {
         when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true));
+        mApexManager.scanApexPackagesTraced(mPackageParser2,
+                ParallelPackageParser.makeExecutorService());
 
         assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue();
     }
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
index 155c6dd..fcbd507 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java
@@ -34,6 +34,7 @@
 import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -54,6 +55,7 @@
  * Tests for {@link TunerResourceManagerService} class.
  */
 @SmallTest
+@Presubmit
 @RunWith(JUnit4.class)
 public class TunerResourceManagerServiceTest {
     private static final String TAG = "TunerResourceManagerServiceTest";
diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
index ab5665b..2ff178e 100644
--- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
+++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.media.tv.TvInputService;
+import android.platform.test.annotations.Presubmit;
 import android.util.Slog;
 
 import androidx.test.filters.SmallTest;
@@ -36,6 +37,7 @@
  * Tests for {@link UseCasePriorityHints} class.
  */
 @SmallTest
+@Presubmit
 @RunWith(JUnit4.class)
 public class UseCasePriorityHintsTest {
     private static final String TAG = "UseCasePriorityHintsTest";
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 52fc3de..12934ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -27,6 +27,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
 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.mock;
@@ -56,7 +57,6 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager;
 import android.app.IApplicationThread;
@@ -1157,6 +1157,34 @@
     }
 
     @Test
+    public void testCheckBehindFullscreenActivity() {
+        final ActivityRecord bottomActivity =
+                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+        final ActivityRecord topActivity =
+                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+        doReturn(true).when(mStack).shouldBeVisible(any());
+        assertTrue(mStack.checkBehindFullscreenActivity(bottomActivity,
+                null /* handleBehindFullscreenActivity */));
+        assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+                null /* handleBehindFullscreenActivity */));
+
+        doReturn(false).when(topActivity).occludesParent();
+        assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
+                null /* handleBehindFullscreenActivity */));
+        assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+                null /* handleBehindFullscreenActivity */));
+
+        final ActivityRecord finishingActivity =
+                new ActivityBuilder(mService).setStack(mStack).setTask(mTask).build();
+        finishingActivity.finishing = true;
+        doCallRealMethod().when(finishingActivity).occludesParent();
+        assertFalse(mStack.checkBehindFullscreenActivity(bottomActivity,
+                null /* handleBehindFullscreenActivity */));
+        assertFalse(mStack.checkBehindFullscreenActivity(topActivity,
+                null /* handleBehindFullscreenActivity */));
+    }
+
+    @Test
     public void testClearUnknownAppVisibilityBehindFullscreenActivity() {
         final UnknownAppVisibilityController unknownAppVisibilityController =
                 mDefaultDisplay.mDisplayContent.mUnknownAppVisibilityController;
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 6ec0f91..ed400ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -82,9 +82,8 @@
 import android.platform.test.annotations.Presubmit;
 import android.service.voice.IVoiceInteractionSession;
 import android.view.Gravity;
-import android.window.IWindowContainer;
-import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
+import android.window.IWindowContainer;
 
 import androidx.test.filters.SmallTest;
 
@@ -975,7 +974,7 @@
 
         // Move activity to split-screen-primary stack and make sure it has the focus.
         TestSplitOrganizer splitOrg = new TestSplitOrganizer(mService, top.getDisplayId());
-        splitOrg.mPrimary.addChild(top.getRootTask(), 0 /* index */);
+        top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
         top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");
 
         // Activity must landed on split-screen-secondary when launch adjacent.
@@ -1001,8 +1000,8 @@
 
     static class TestSplitOrganizer extends ITaskOrganizer.Stub {
         final ActivityTaskManagerService mService;
-        TaskTile mPrimary;
-        TaskTile mSecondary;
+        Task mPrimary;
+        Task mSecondary;
         boolean mInSplit = false;
         int mDisplayId;
         TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
@@ -1014,10 +1013,10 @@
                     WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
             IWindowContainer primary = mService.mTaskOrganizerController.createRootTask(
                     displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
-            mPrimary = TaskTile.forToken(primary.asBinder());
+            mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
             IWindowContainer secondary = mService.mTaskOrganizerController.createRootTask(
                     displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
-            mSecondary = TaskTile.forToken(secondary.asBinder());
+            mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
         }
         @Override
         public void onTaskAppeared(ActivityManager.RunningTaskInfo info) {
@@ -1042,7 +1041,7 @@
                     for (int i = dc.getStackCount() - 1; i >= 0; --i) {
                         if (!WindowConfiguration.isSplitScreenWindowingMode(
                                 dc.getStackAt(i).getWindowingMode())) {
-                            mSecondary.addChild(dc.getStackAt(i), 0);
+                            dc.getStackAt(i).reparent(mSecondary, POSITION_BOTTOM);
                         }
                     }
                 }
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 4634e2d..716369d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -464,7 +464,7 @@
         ActivityStack build() {
             final int stackId = mStackId >= 0 ? mStackId : mDisplay.getNextStackId();
             final ActivityStack stack = mDisplay.createStackUnchecked(mWindowingMode,
-                    mActivityType, stackId, mOnTop, mInfo, mIntent);
+                    mActivityType, stackId, mOnTop, mInfo, mIntent, false /* createdByOrganizer */);
             final ActivityStackSupervisor supervisor = mRootWindowContainer.mStackSupervisor;
 
             if (mCreateActivity) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index bfb126f..db7bce4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -19,10 +19,12 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
@@ -147,6 +149,61 @@
     }
 
     @Test
+    public void testStripForDispatch_belowIme() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+        getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+        assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+    }
+
+    @Test
+    public void testStripForDispatch_aboveIme() {
+        final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+        getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+        assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_IME));
+    }
+
+    @Test
+    public void testStripForDispatch_childWindow_altFocusable() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+        final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+        child.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM;
+
+        final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+        // IME cannot be the IME target.
+        ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+
+        getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+        assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
+    }
+
+    @Test
+    public void testStripForDispatch_childWindow_splitScreen() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+        final WindowState child = createWindow(app, TYPE_APPLICATION, "child");
+        child.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+        child.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+
+        final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
+
+        // IME cannot be the IME target.
+        ime.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
+
+        getController().getSourceProvider(ITYPE_IME).setWindow(ime, null, null);
+
+        assertNull(getController().getInsetsForDispatch(child).peekSource(ITYPE_IME));
+    }
+
+    @Test
     public void testImeForDispatch() {
         final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
         final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
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 66566bc..da3ee39 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -28,6 +29,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.TYPE_VIRTUAL;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -54,6 +56,7 @@
 
 import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -681,24 +684,19 @@
      * Tests that tasks on singleTaskDisplay are not visible and not trimmed/removed.
      */
     @Test
-    public void testVisibleTasks_singleTaskDisplay() {
+    public void testVisibleTasks_alwaysOnTop() {
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
 
-        final DisplayContent singleTaskDisplay =
-                addNewDisplayContentAt(DisplayContent.POSITION_TOP);
-        singleTaskDisplay.setDisplayToSingleTaskInstance();
-        ActivityStack singleTaskStack = singleTaskDisplay.createStack(
-                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
+        final Task alwaysOnTopTask = display.createStack(WINDOWING_MODE_MULTI_WINDOW,
+                ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        alwaysOnTopTask.setAlwaysOnTop(true);
 
-        Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
-                .setStack(singleTaskStack)
-                .build();
+        assertFalse("Always on top tasks should not be visible recents",
+                mRecentTasks.isVisibleRecentTask(alwaysOnTopTask));
 
-        assertFalse("Tasks on singleTaskDisplay should not be visible recents",
-                mRecentTasks.isVisibleRecentTask(excludedTask1));
-
-        mRecentTasks.add(excludedTask1);
+        mRecentTasks.add(alwaysOnTopTask);
 
         // Add N+1 visible tasks.
         mRecentTasks.add(mTasks.get(0));
@@ -1366,12 +1364,12 @@
         public boolean mLastAllowed;
 
         @Override
-        void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType,
-                int ignoreWindowingMode, RootWindowContainer root,
-                int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) {
+        void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents,
+                RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser,
+                ArraySet<Integer> profileIds) {
             mLastAllowed = allowed;
-            super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, root,
-                    callingUid, allowed, crossUser, profileIds);
+            super.getTasks(maxNum, list, filterOnlyVisibleRecents, root, callingUid, allowed,
+                    crossUser, profileIds);
         }
     }
 }
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 406affc..f242989 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -403,11 +403,11 @@
                 wallpapers.get(0).getConfiguration().orientation);
 
         // Wallpaper's transform state is controlled by home, so the invocation should be no-op.
-        wallpaperWindowToken.clearFixedRotationTransform();
+        wallpaperWindowToken.finishFixedRotationTransform();
         assertTrue(wallpaperWindowToken.hasFixedRotationTransform());
 
         // Wallpaper's transform state should be cleared with home.
-        homeActivity.clearFixedRotationTransform();
+        homeActivity.finishFixedRotationTransform();
         assertFalse(wallpaperWindowToken.hasFixedRotationTransform());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 0ef2582..e841e43 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -788,6 +788,22 @@
     }
 
     @Test
+    public void testGetValidLaunchStackOnDisplayWithCandidateRootTask() {
+        // Create a root task with an activity on secondary display.
+        final TestDisplayContent secondaryDisplay = new TestDisplayContent.Builder(mService, 300,
+                600).build();
+        final Task task = new ActivityTestsBase.StackBuilder(mRootWindowContainer).setDisplay(
+                secondaryDisplay).build();
+        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(mService)
+                .setTask(task).build();
+
+        // Make sure the root task is valid and can be reused on default display.
+        final ActivityStack stack = mRootWindowContainer.getValidLaunchStackOnDisplay(
+                DEFAULT_DISPLAY, activity, task, null, null);
+        assertEquals(task, stack);
+    }
+
+    @Test
     public void testSwitchUser_missingHomeRootTask() {
         doReturn(mFullscreenStack).when(mRootWindowContainer).getTopDisplayFocusedStack();
 
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 0d55654..d6a67ab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -82,9 +79,8 @@
         // collected from all tasks across all the stacks
         final int numFetchTasks = 5;
         ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
-        mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
-                mRootWindowContainer, -1 /* callingUid */, true /* allowed */,
-                true /*crossUser */, PROFILE_IDS);
+        mRunningTasks.getTasks(5, tasks, false /* filterOnlyVisibleRecents */, mRootWindowContainer,
+                -1 /* callingUid */, true /* allowed */, true /*crossUser */, PROFILE_IDS);
         assertThat(tasks).hasSize(numFetchTasks);
         for (int i = 0; i < numFetchTasks; i++) {
             assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -93,9 +89,9 @@
         // Ensure that requesting more than the total number of tasks only returns the subset
         // and does not crash
         tasks.clear();
-        mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED,
-                mRootWindowContainer, -1 /* callingUid */, true /* allowed */,
-                true /* crossUser */, PROFILE_IDS);
+        mRunningTasks.getTasks(100, tasks, false /* filterOnlyVisibleRecents */,
+                mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /* crossUser */,
+                PROFILE_IDS);
         assertThat(tasks).hasSize(numTasks);
         for (int i = 0; i < numTasks; i++) {
             assertEquals(numTasks - i - 1, tasks.get(i).id);
@@ -119,9 +115,9 @@
 
         final int numFetchTasks = 5;
         final ArrayList<RunningTaskInfo> tasks = new ArrayList<>();
-        mRunningTasks.getTasks(numFetchTasks, tasks, ACTIVITY_TYPE_UNDEFINED,
-                WINDOWING_MODE_UNDEFINED, mRootWindowContainer, -1 /* callingUid */,
-                true /* allowed */, true /*crossUser */, PROFILE_IDS);
+        mRunningTasks.getTasks(numFetchTasks, tasks, false /* filterOnlyVisibleRecents */,
+                mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /*crossUser */,
+                PROFILE_IDS);
         assertThat(tasks).hasSize(numFetchTasks);
         for (int i = 0; i < tasks.size(); i++) {
             final Bundle extras = tasks.get(i).baseIntent.getExtras();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index a96f401..ed635ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -37,6 +37,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -347,45 +348,62 @@
         assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType);
 
         DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
-        List<TaskTile> infos = getTaskTiles(dc);
+        List<Task> infos = getTasksCreatedByOrganizer(dc);
         assertEquals(2, infos.size());
 
         assertTrue(mWm.mAtmService.mTaskOrganizerController.deleteRootTask(info1.token));
-        infos = getTaskTiles(dc);
+        infos = getTasksCreatedByOrganizer(dc);
         assertEquals(1, infos.size());
         assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, infos.get(0).getWindowingMode());
     }
 
     @Test
     public void testTileAddRemoveChild() {
+        ITaskOrganizer listener = new ITaskOrganizer.Stub() {
+            @Override
+            public void onTaskAppeared(RunningTaskInfo taskInfo) { }
+
+            @Override
+            public void onTaskVanished(RunningTaskInfo container) { }
+
+            @Override
+            public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException {
+            }
+        };
+        mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
+                WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
         RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
 
         final ActivityStack stack = createTaskStackOnDisplay(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
-        TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
-        tile1.addChild(stack, 0 /* index */);
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
         assertEquals(info1.configuration.windowConfiguration.getWindowingMode(),
                 stack.getWindowingMode());
 
         // Info should reflect new membership
-        List<TaskTile> tiles = getTaskTiles(mDisplayContent);
-        info1 = tiles.get(0).getTaskInfo();
+        List<Task> infos = getTasksCreatedByOrganizer(mDisplayContent);
+        info1 = infos.get(0).getTaskInfo();
         assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType);
 
         // Children inherit configuration
         Rect newSize = new Rect(10, 10, 300, 300);
-        Configuration c = new Configuration(tile1.getRequestedOverrideConfiguration());
+        Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
+        Configuration c = new Configuration(task1.getRequestedOverrideConfiguration());
         c.windowConfiguration.setBounds(newSize);
         doNothing().when(stack).adjustForMinimalTaskDimensions(any(), any());
-        tile1.onRequestedOverrideConfigurationChanged(c);
+        task1.onRequestedOverrideConfigurationChanged(c);
         assertEquals(newSize, stack.getBounds());
 
-        tile1.removeChild(stack);
+        wct = new WindowContainerTransaction();
+        wct.reparent(stack.mRemoteToken, null, true /* onTop */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
         assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
-        tiles = getTaskTiles(mDisplayContent);
-        info1 = tiles.get(0).getTaskInfo();
+        infos = getTasksCreatedByOrganizer(mDisplayContent);
+        info1 = infos.get(0).getTaskInfo();
         assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
     }
 
@@ -415,8 +433,10 @@
 
         final ActivityStack stack = createTaskStackOnDisplay(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
-        TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
-        tile1.addChild(stack, 0 /* index */);
+        Task task1 = WindowContainer.fromBinder(info1.token.asBinder()).asTask();
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        wct.reparent(stack.mRemoteToken, info1.token, true /* onTop */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
         assertTrue(called[0]);
         assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
 
@@ -424,19 +444,24 @@
         called[0] = false;
         final ActivityStack stack2 = createTaskStackOnDisplay(
                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
-        tile1.addChild(stack2, 0 /* index */);
+        wct = new WindowContainerTransaction();
+        wct.reparent(stack2.mRemoteToken, info1.token, true /* onTop */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
         assertTrue(called[0]);
         assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType);
 
         lastReportedTiles.clear();
         called[0] = false;
-        mDisplayContent.positionStackAtTop(stack, false /* includingParents */);
+        task1.positionChildAt(POSITION_TOP, stack, false /* includingParents */);
         assertTrue(called[0]);
         assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
 
         lastReportedTiles.clear();
         called[0] = false;
-        tile1.removeAllChildren();
+        wct = new WindowContainerTransaction();
+        wct.reparent(stack.mRemoteToken, null, true /* onTop */);
+        wct.reparent(stack2.mRemoteToken, null, true /* onTop */);
+        mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
         assertTrue(called[0]);
         assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
     }
@@ -457,9 +482,11 @@
             }
         };
         mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
+                listener, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+        mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
                 listener, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
         RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
-                mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
                 mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
 
@@ -522,13 +549,11 @@
                 lastReportedTiles.get(info1.token.asBinder()).topActivityType);
     }
 
-    private List<TaskTile> getTaskTiles(DisplayContent dc) {
-        ArrayList<TaskTile> out = new ArrayList<>();
+    private List<Task> getTasksCreatedByOrganizer(DisplayContent dc) {
+        ArrayList<Task> out = new ArrayList<>();
         for (int i = dc.getStackCount() - 1; i >= 0; --i) {
-            final TaskTile t = dc.getStackAt(i).asTile();
-            if (t != null) {
-                out.add(t);
-            }
+            final Task t = dc.getStackAt(i);
+            if (t.mCreatedByOrganizer) out.add(t);
         }
         return out;
     }
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 a25acae..56c19a4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -27,6 +27,7 @@
 import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
@@ -151,7 +152,7 @@
             assertFalse(factory.mCreated);
 
             Task.create(mService, 0 /*taskId*/, 0 /*activityType*/,
-                    new ActivityInfo(), new Intent());
+                    new ActivityInfo(), new Intent(), false /* createdByOrganizer */);
 
             assertTrue(factory.mCreated);
         } finally {
@@ -939,6 +940,20 @@
         verify(persister, never()).saveTask(same(task), any());
     }
 
+    @Test
+    public void testNotSpecifyOrientationByFloatingTask() {
+        final Task task = getTestTask();
+        final ActivityRecord activity = task.getTopMostActivity();
+        final WindowContainer<?> taskContainer = task.getParent();
+        activity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, taskContainer.getOrientation());
+
+        task.setWindowingMode(WINDOWING_MODE_PINNED);
+
+        assertEquals(SCREEN_ORIENTATION_UNSET, taskContainer.getOrientation());
+    }
+
     private Task getTestTask() {
         final ActivityStack stack = new StackBuilder(mRootWindowContainer).build();
         return stack.getBottomMostTask();
@@ -1000,7 +1015,7 @@
 
         @Override
         Task create(ActivityTaskManagerService service, int taskId, int activityType,
-                ActivityInfo info, Intent intent) {
+                ActivityInfo info, Intent intent, boolean createdByOrganizer) {
             mCreated = true;
             return null;
         }
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 85e4a16..e95ccab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -251,11 +251,9 @@
 
         // b/145812508: special legacy use-case for transparent/translucent windows.
         appWindow.mAttrs.format = PixelFormat.TRANSPARENT;
-        appWindow.mAttrs.alpha = 0;
         assertTrue(appWindow.canBeImeTarget());
 
         appWindow.mAttrs.format = PixelFormat.OPAQUE;
-        appWindow.mAttrs.alpha = 1;
         appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
         assertFalse(appWindow.canBeImeTarget());
         appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 3196758..00cb6dc 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -207,7 +207,13 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (PHASE_SYSTEM_SERVICES_READY == phase) {
+        Slog.d(TAG, "onBootPhase: " + phase + " : " + isSafeMode());
+        if (PHASE_DEVICE_SPECIFIC_SERVICES_READY == phase) {
+            if (isSafeMode()) {
+                Slog.w(TAG, "not enabling SoundTriggerService in safe mode");
+                return;
+            }
+
             initSoundTriggerHelper();
             mLocalSoundTriggerService.setSoundTriggerHelper(mSoundTriggerHelper);
         } else if (PHASE_THIRD_PARTY_APPS_CAN_START == phase) {
diff --git a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
index 488ee78..47bf148 100644
--- a/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
+++ b/startop/iorap/src/com/google/android/startop/iorap/EventSequenceValidator.java
@@ -23,6 +23,9 @@
 
 import com.android.server.wm.ActivityMetricsLaunchObserver;
 
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
 /**
  * A validator to check the correctness of event sequence during app startup.
  *
@@ -100,7 +103,8 @@
   @Override
   public void onIntentStarted(@NonNull Intent intent, long timestampNs) {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "IntentStarted during UNKNOWN." + intent);
+      logWarningWithStackTrace(
+          String.format("IntentStarted during UNKNOWN. " + intent));
       incAccIntentStartedEvents();
       return;
     }
@@ -110,7 +114,7 @@
         state != State.ACTIVITY_CANCELLED &&
         state != State.ACTIVITY_FINISHED &&
         state != State.REPORT_FULLY_DRAWN) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.INTENT_STARTED));
       incAccIntentStartedEvents();
       incAccIntentStartedEvents();
@@ -124,12 +128,12 @@
   @Override
   public void onIntentFailed() {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "IntentFailed during UNKNOWN.");
+      logWarningWithStackTrace(String.format("onIntentFailed during UNKNOWN."));
       decAccIntentStartedEvents();
       return;
     }
     if (state != State.INTENT_STARTED) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.INTENT_FAILED));
       incAccIntentStartedEvents();
       return;
@@ -143,11 +147,12 @@
   public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity,
       @Temperature int temperature) {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "onActivityLaunched during UNKNOWN.");
+      logWarningWithStackTrace(
+          String.format("onActivityLaunched during UNKNOWN."));
       return;
     }
     if (state != State.INTENT_STARTED) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.ACTIVITY_LAUNCHED));
       incAccIntentStartedEvents();
       return;
@@ -160,12 +165,13 @@
   @Override
   public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] activity) {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "onActivityLaunchCancelled during UNKNOWN.");
+      logWarningWithStackTrace(
+          String.format("onActivityLaunchCancelled during UNKNOWN."));
       decAccIntentStartedEvents();
       return;
     }
     if (state != State.ACTIVITY_LAUNCHED) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.ACTIVITY_CANCELLED));
       incAccIntentStartedEvents();
       return;
@@ -179,13 +185,14 @@
   public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] activity,
       long timestampNs) {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "onActivityLaunchFinished during UNKNOWN.");
+      logWarningWithStackTrace(
+          String.format("onActivityLaunchFinished during UNKNOWN."));
       decAccIntentStartedEvents();
       return;
     }
 
     if (state != State.ACTIVITY_LAUNCHED) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.ACTIVITY_FINISHED));
       incAccIntentStartedEvents();
       return;
@@ -199,7 +206,8 @@
   public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity,
       long timestampNs) {
     if (state == State.UNKNOWN) {
-      Log.wtf(TAG, "onReportFullyDrawn during UNKNOWN.");
+      logWarningWithStackTrace(
+          String.format("onReportFullyDrawn during UNKNOWN."));
       return;
     }
     if (state == State.INIT) {
@@ -207,7 +215,7 @@
     }
 
     if (state != State.ACTIVITY_FINISHED) {
-      Log.wtf(TAG,
+      logWarningWithStackTrace(
           String.format("Cannot transition from %s to %s", state, State.REPORT_FULLY_DRAWN));
       return;
     }
@@ -252,4 +260,11 @@
     Log.i(TAG,
         String.format("dec AccIntentStartedEvents to %d", accIntentStartedEvents));
   }
+
+  private void logWarningWithStackTrace(String log) {
+    StringWriter sw = new StringWriter();
+    PrintWriter pw = new PrintWriter(sw);
+    new Throwable("EventSequenceValidator#getStackTrace").printStackTrace(pw);
+    Log.w(TAG, String.format("%s\n%s", log, sw));
+  }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0dca006..ffd25c0 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2633,6 +2633,7 @@
      * @param request Details about the incoming call.
      * @return The {@code Connection} object to satisfy this call, or {@code null} to
      *         not handle the call.
+     * @hide
      */
     public @Nullable Conference onCreateIncomingConference(
             @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2717,6 +2718,7 @@
      * @param connectionManagerPhoneAccount See description at
      *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
      * @param request The incoming connection request.
+     * @hide
      */
     public void onCreateIncomingConferenceFailed(
             @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2737,6 +2739,7 @@
      * @param connectionManagerPhoneAccount See description at
      *         {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
      * @param request The outgoing connection request.
+     * @hide
      */
     public void onCreateOutgoingConferenceFailed(
             @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2805,6 +2808,7 @@
      * @param request Details about the outgoing call.
      * @return The {@code Conference} object to satisfy this call, or the result of an invocation
      *         of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
+     * @hide
      */
     public @Nullable Conference onCreateOutgoingConference(
             @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 0b33174..7e02966 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -442,16 +442,40 @@
         // NOTE(b/73308711): If an app has one of the following AppOps bits explicitly revoked, they
         // will be denied access, even if they have another permission and AppOps bit if needed.
 
-        // First, check if we can read the phone state and the SDK version is below R.
+        // First, check if the SDK version is below R
+        boolean preR = false;
         try {
             ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser(
                     callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid()));
-            if (info.targetSdkVersion <= Build.VERSION_CODES.Q) {
+            preR = info.targetSdkVersion <= Build.VERSION_CODES.Q;
+        } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+        }
+        if (preR) {
+            // SDK < R allows READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier privilege
+            try {
                 return checkReadPhoneState(
                         context, subId, pid, uid, callingPackage, callingFeatureId, message);
+            } catch (SecurityException readPhoneStateException) {
             }
-        } catch (SecurityException | PackageManager.NameNotFoundException e) {
+        } else {
+            // SDK >= R allows READ_PRIVILEGED_PHONE_STATE or carrier privilege
+            try {
+                context.enforcePermission(
+                        android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message);
+                // Skip checking for runtime permission since caller has privileged permission
+                return true;
+            } catch (SecurityException readPrivilegedPhoneStateException) {
+                if (SubscriptionManager.isValidSubscriptionId(subId)) {
+                    try {
+                        enforceCarrierPrivilege(context, subId, uid, message);
+                        // Skip checking for runtime permission since caller has carrier privilege
+                        return true;
+                    } catch (SecurityException carrierPrivilegeException) {
+                    }
+                }
+            }
         }
+
         // Can be read with READ_SMS too.
         try {
             context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message);
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 558f4cd..39a7543 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -19,9 +19,9 @@
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
-import android.hardware.radio.V1_1.EutranBands;
 import android.hardware.radio.V1_1.GeranBands;
 import android.hardware.radio.V1_5.AccessNetwork;
+import android.hardware.radio.V1_5.EutranBands;
 import android.hardware.radio.V1_5.UtranBands;
 
 import java.lang.annotation.Retention;
@@ -212,7 +212,8 @@
 
     /**
      * Frequency bands for EUTRAN.
-     * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf
+     * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands
+     * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf
      */
     public static final class EutranBand {
         public static final int BAND_1 = EutranBands.BAND_1;
@@ -259,10 +260,22 @@
         public static final int BAND_46 = EutranBands.BAND_46;
         public static final int BAND_47 = EutranBands.BAND_47;
         public static final int BAND_48 = EutranBands.BAND_48;
+        public static final int BAND_49 = EutranBands.BAND_49;
+        public static final int BAND_50 = EutranBands.BAND_50;
+        public static final int BAND_51 = EutranBands.BAND_51;
+        public static final int BAND_52 = EutranBands.BAND_52;
+        public static final int BAND_53 = EutranBands.BAND_53;
         public static final int BAND_65 = EutranBands.BAND_65;
         public static final int BAND_66 = EutranBands.BAND_66;
         public static final int BAND_68 = EutranBands.BAND_68;
         public static final int BAND_70 = EutranBands.BAND_70;
+        public static final int BAND_71 = EutranBands.BAND_71;
+        public static final int BAND_72 = EutranBands.BAND_72;
+        public static final int BAND_73 = EutranBands.BAND_73;
+        public static final int BAND_74 = EutranBands.BAND_74;
+        public static final int BAND_85 = EutranBands.BAND_85;
+        public static final int BAND_87 = EutranBands.BAND_87;
+        public static final int BAND_88 = EutranBands.BAND_88;
 
         /** @hide */
         private EutranBand() {};
@@ -305,9 +318,11 @@
 
     /**
      * Frequency bands for NGRAN
+     * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810101/15.08.02_60/ts_13810101v150802p.pdf
+     * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf
      */
     public static final class NgranBands {
-        /** FR1 bands */
+        /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */
         public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1;
         public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2;
         public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3;
@@ -346,9 +361,15 @@
         public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83;
         public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84;
         public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86;
+        public static final int BAND_89 = android.hardware.radio.V1_5.NgranBands.BAND_89;
         public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90;
+        public static final int BAND_91 = android.hardware.radio.V1_5.NgranBands.BAND_91;
+        public static final int BAND_92 = android.hardware.radio.V1_5.NgranBands.BAND_92;
+        public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93;
+        public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94;
+        public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95;
 
-        /** FR2 bands */
+        /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */
         public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257;
         public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258;
         public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260;
@@ -398,7 +419,13 @@
                         BAND_83,
                         BAND_84,
                         BAND_86,
+                        BAND_89,
                         BAND_90,
+                        BAND_91,
+                        BAND_92,
+                        BAND_93,
+                        BAND_94,
+                        BAND_95,
                         BAND_257,
                         BAND_258,
                         BAND_260,
@@ -495,7 +522,13 @@
                 case BAND_83:
                 case BAND_84:
                 case BAND_86:
+                case BAND_89:
                 case BAND_90:
+                case BAND_91:
+                case BAND_92:
+                case BAND_93:
+                case BAND_94:
+                case BAND_95:
                     return FREQUENCY_RANGE_GROUP_1;
                 case BAND_257:
                 case BAND_258:
diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java
index 5d2c225..981ed450 100644
--- a/telephony/java/android/telephony/AccessNetworkUtils.java
+++ b/telephony/java/android/telephony/AccessNetworkUtils.java
@@ -34,12 +34,10 @@
             return DUPLEX_MODE_UNKNOWN;
         }
 
-        if (band >= EutranBand.BAND_68) {
+        if (band > EutranBand.BAND_88) {
             return DUPLEX_MODE_UNKNOWN;
         } else if (band >= EutranBand.BAND_65) {
             return DUPLEX_MODE_FDD;
-        } else if (band >= EutranBand.BAND_47) {
-            return DUPLEX_MODE_UNKNOWN;
         } else if (band >= EutranBand.BAND_33) {
             return DUPLEX_MODE_TDD;
         } else if (band >= EutranBand.BAND_1) {
@@ -58,17 +56,53 @@
      * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists
      */
     public static int getOperatingBandForEarfcn(int earfcn) {
-        if (earfcn > 67535) {
+        if (earfcn > 70645) {
             return INVALID_BAND;
+        } else if (earfcn >= 70596) {
+            return EutranBand.BAND_88;
+        } else if (earfcn >= 70546) {
+            return EutranBand.BAND_87;
+        } else if (earfcn >= 70366) {
+            return EutranBand.BAND_85;
+        } else if (earfcn > 69465) {
+            return INVALID_BAND;
+        } else if (earfcn >= 69036) {
+            return EutranBand.BAND_74;
+        } else if (earfcn >= 68986) {
+            return EutranBand.BAND_73;
+        } else if (earfcn >= 68936) {
+            return EutranBand.BAND_72;
+        } else if (earfcn >= 68586) {
+            return EutranBand.BAND_71;
+        } else if (earfcn >= 68336) {
+            return EutranBand.BAND_70;
+        } else if (earfcn > 67835) {
+            return INVALID_BAND;
+        } else if (earfcn >= 67536) {
+            return EutranBand.BAND_68;
         } else if (earfcn >= 67366) {
             return INVALID_BAND; // band 67 only for CarrierAgg
         } else if (earfcn >= 66436) {
             return EutranBand.BAND_66;
         } else if (earfcn >= 65536) {
             return EutranBand.BAND_65;
-        } else if (earfcn > 54339) {
+        } else if (earfcn > 60254) {
             return INVALID_BAND;
-        } else if (earfcn >= 46790 /* inferred from the end range of BAND_45 */) {
+        } else if (earfcn >= 60140) {
+            return EutranBand.BAND_53;
+        } else if (earfcn >= 59140) {
+            return EutranBand.BAND_52;
+        } else if (earfcn >= 59090) {
+            return EutranBand.BAND_51;
+        } else if (earfcn >= 58240) {
+            return EutranBand.BAND_50;
+        } else if (earfcn >= 56740) {
+            return EutranBand.BAND_49;
+        } else if (earfcn >= 55240) {
+            return EutranBand.BAND_48;
+        } else if (earfcn >= 54540) {
+            return EutranBand.BAND_47;
+        } else if (earfcn >= 46790) {
             return EutranBand.BAND_46;
         } else if (earfcn >= 46590) {
             return EutranBand.BAND_45;
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 1c92705b..d00049c 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -314,6 +314,8 @@
 
     /**
      * Get the signal strength as dBm
+     *
+     * @return min(CDMA RSSI, EVDO RSSI) of the measured cell.
      */
     @Override
     public int getDbm() {
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 76d2df9..9d55f10 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -145,6 +145,8 @@
 
     /**
      * Get the signal strength as dBm.
+     *
+     * @return the RSSI of the measured cell.
      */
     @Override
     public int getDbm() {
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index c144746..991375c 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2520,7 +2520,6 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed
      * @throws IllegalArgumentException if contentUri is empty
-     * @deprecated use {@link MmsManager#sendMultimediaMessage} instead.
      */
     public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
             Bundle configOverrides, PendingIntent sentIntent) {
@@ -2555,7 +2554,6 @@
      * @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
-     * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead.
      */
     public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
             Bundle configOverrides, PendingIntent downloadedIntent) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 5d3cc44..2facd5a 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -944,6 +944,18 @@
             if (DBG) log("onSubscriptionsChanged: NOT OVERRIDDEN");
         }
 
+        /**
+         * Callback invoked when {@link SubscriptionManager#addOnSubscriptionsChangedListener(
+         * Executor, OnSubscriptionsChangedListener)} or
+         * {@link SubscriptionManager#addOnSubscriptionsChangedListener(
+         * OnSubscriptionsChangedListener)} fails to complete due to the
+         * {@link Context#TELEPHONY_REGISTRY_SERVICE} being unavailable.
+         * @hide
+         */
+        public void onAddListenerFailed() {
+            Rlog.w(LOG_TAG, "onAddListenerFailed not overridden");
+        }
+
         private void log(String s) {
             Rlog.d(LOG_TAG, s);
         }
@@ -1012,6 +1024,12 @@
         if (telephonyRegistryManager != null) {
             telephonyRegistryManager.addOnSubscriptionsChangedListener(listener,
                     executor);
+        } else {
+            // If the telephony registry isn't available, we will inform the caller on their
+            // listener that it failed so they can try to re-register.
+            loge("addOnSubscriptionsChangedListener: pkgname=" + pkgName + " failed to be added "
+                    + " due to TELEPHONY_REGISTRY_SERVICE being unavailable.");
+            executor.execute(() -> listener.onAddListenerFailed());
         }
     }
 
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index bb4e00b..f2f0be7 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -223,7 +223,7 @@
     public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
             int stepCount) {
         int screenHeight =
-                activity.getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
+                activity.getWindowManager().getCurrentWindowMetrics().getBounds().height();
 
         int[] xy = new int[2];
         v.getLocationOnScreen(xy);
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 9be97b5..0ad3039 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -46,6 +46,7 @@
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -72,6 +73,7 @@
     private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
     private static final String KEY_APPS = "apps";
     private static final String KEY_IORAP_TRIAL_LAUNCH = "iorap_trial_launch";
+    private static final String KEY_IORAP_COMPILER_FILTERS = "iorap_compiler_filters";
     private static final String KEY_TRIAL_LAUNCH = "trial_launch";
     private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
     private static final String KEY_LAUNCH_ORDER = "launch_order";
@@ -153,6 +155,7 @@
     private BufferedWriter mBufferedWriter = null;
     private boolean mSimplePerfAppOnly = false;
     private String[] mCompilerFilters = null;
+    private List<String> mIorapCompilerFilters = null;
     private String mLastAppName = "";
     private boolean mCycleCleanUp = false;
     private boolean mTraceAll = false;
@@ -618,6 +621,24 @@
         return reason;
     }
 
+    private boolean shouldIncludeIorap(String compilerFilter) {
+        if (!mIorapTrialLaunch) {
+            return false;
+        }
+
+        // No iorap compiler filters specified: treat all compiler filters as ok.
+        if (mIorapCompilerFilters == null) {
+            return true;
+        }
+
+        // iorap compiler filters specified: the compilerFilter must be in the whitelist.
+        if (mIorapCompilerFilters.indexOf(compilerFilter) != -1) {
+            return true;
+        }
+
+        return false;
+    }
+
     /**
      * If launch order is "cyclic" then apps will be launched one after the
      * other for each iteration count.
@@ -632,7 +653,7 @@
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
                     }
                 }
-                if (mIorapTrialLaunch) {
+                if (shouldIncludeIorap(compilerFilter)) {
                     for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
                         for (String app : mNameToResultKey.keySet()) {
                             String reason = makeReasonForIorapTrialLaunch(launchCount);
@@ -646,14 +667,16 @@
                 for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
                     for (String app : mNameToResultKey.keySet()) {
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                  String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
+                                  String.format(LAUNCH_ITERATION, launchCount),
+                                        shouldIncludeIorap(compilerFilter)));
                     }
                 }
                 if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
                     for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
                         for (String app : mNameToResultKey.keySet()) {
                             mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                      String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
+                                      String.format(TRACE_ITERATION, traceCount),
+                                            shouldIncludeIorap(compilerFilter)));
                         }
                     }
                 }
@@ -664,7 +687,7 @@
                     if (mTrialLaunch) {
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false));
                     }
-                    if (mIorapTrialLaunch) {
+                    if (shouldIncludeIorap(compilerFilter)) {
                         for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) {
                             String reason = makeReasonForIorapTrialLaunch(launchCount);
                             mLaunchOrderList.add(
@@ -675,12 +698,14 @@
                     }
                     for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
                         mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch));
+                                String.format(LAUNCH_ITERATION, launchCount),
+                                        shouldIncludeIorap(compilerFilter)));
                     }
                     if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
                         for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
                             mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
-                                    String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch));
+                                    String.format(TRACE_ITERATION, traceCount),
+                                            shouldIncludeIorap(compilerFilter)));
                         }
                     }
                 }
@@ -767,7 +792,7 @@
                 .executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable));
         getInstrumentation().getUiAutomation()
                 .executeShellCommand("start iorapd");
-        sleep(2000);  // give enough time for iorapd to start back up.
+        sleep(3000);  // give enough time for iorapd to start back up.
 
         if (enable) {
             mIorapStatus = IorapStatus.ENABLED;
@@ -822,6 +847,13 @@
             mCompilerFilters = new String[1];
         }
 
+        String iorapCompilerFilterList = args.getString(KEY_IORAP_COMPILER_FILTERS);
+        if (iorapCompilerFilterList != null) {
+            // Passing in iorap compiler filters implies an iorap trial launch.
+            mIorapTrialLaunch = true;
+            mIorapCompilerFilters = Arrays.asList(iorapCompilerFilterList.split("\\|"));
+        }
+
         // Pre-populate the results map to avoid null checks.
         for (String app : mNameToLaunchTime.keySet()) {
             HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
index 42908be..35a6c26 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
@@ -167,7 +167,7 @@
 
         final byte[] actualBytes = new byte[lengthBytes];
         try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
-                session.openWrite(0L, 0L))) {
+                session.openRead())) {
             read(in, actualBytes, offsetBytes, lengthBytes);
         }
 
@@ -190,7 +190,7 @@
             long offsetBytes, long lengthBytes) throws Exception {
         final byte[] actualDigest;
         try (FileInputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
-                session.openWrite(0L, 0L))) {
+                session.openRead())) {
             actualDigest = createSha256Digest(in, offsetBytes, lengthBytes);
         }
 
diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
index e255ce2..31532a2 100644
--- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
+++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
@@ -27,7 +27,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
-import android.util.Size;
 import android.view.Gravity;
 import android.view.IWindowManager;
 import android.view.MotionEvent;
@@ -90,8 +89,8 @@
                 .getSystemService(WindowManager.class);
         mIWm = WindowManagerGlobal.getWindowManagerService();
 
-        Size windowSize = mWm.getCurrentWindowMetrics().getSize();
-        mWindowBounds.set(0, 0, windowSize.getWidth(), windowSize.getHeight());
+        Rect windowBounds = mWm.getCurrentWindowMetrics().getBounds();
+        mWindowBounds.set(0, 0, windowBounds.width(), windowBounds.height());
 
         mScaleText = findViewById(R.id.scale);
         mDisplayFrameText = findViewById(R.id.displayFrame);
diff --git a/tests/RollbackTest/RollbackTest.xml b/tests/RollbackTest/RollbackTest.xml
index 269cec1..7b85cc8 100644
--- a/tests/RollbackTest/RollbackTest.xml
+++ b/tests/RollbackTest/RollbackTest.xml
@@ -23,6 +23,10 @@
         <option name="run-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\\*' --esa flags &quot;ModuleConfig__versioned_immediate_commit_packages&quot; --esa types &quot;bytes&quot; --esa values &quot;Cm5vdGFwYWNrYWdlOgA=&quot; com.google.android.gms" />
         <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__immediate_commit_packages&quot; com.google.android.gms" />
         <option name="teardown-command" value="am broadcast -a 'com.google.android.gms.phenotype.FLAG_OVERRIDE' --es action delete --es package &quot;com.google.android.gms.platformconfigurator&quot; --es user '\*' --esa flag &quot;ModuleConfig__versioned_immediate_commit_packages&quot; com.google.android.gms" />
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+        <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+        <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.tests.rollback" />
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 5a92d68..cab8b42 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -75,6 +75,12 @@
     private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS =
             "enable_rollback_timeout";
 
+    private static boolean hasRollbackInclude(List<RollbackInfo> rollbacks, String packageName) {
+        return rollbacks.stream().anyMatch(
+                ri -> ri.getPackages().stream().anyMatch(
+                        pri -> packageName.equals(pri.getPackageName())));
+    }
+
     /**
      * Test basic rollbacks.
      */
@@ -113,18 +119,14 @@
             // Uninstall TestApp.A
             Uninstall.packages(TestApp.A);
             assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
-            // TODO: There is currently a race condition between when the app is
-            // uninstalled and when rollback manager deletes the rollback. Fix it
-            // so that's not the case!
             for (int i = 0; i < 5; ++i) {
-                RollbackInfo rollback = getUniqueRollbackInfoForPackage(
-                        rm.getRecentlyCommittedRollbacks(), TestApp.A);
-                if (rollback != null) {
+                if (hasRollbackInclude(rm.getRecentlyCommittedRollbacks(), TestApp.A)) {
                     Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
                     Thread.sleep(1000);
                 }
             }
 
+            assertThat(hasRollbackInclude(rm.getRecentlyCommittedRollbacks(), TestApp.A)).isFalse();
             // The app should not be available for rollback.
             waitForUnavailableRollback(TestApp.A);
 
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index b2e8c37..916c339 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -463,7 +463,9 @@
 
         nc1.setSSID(TEST_SSID);
         nc2.combineCapabilities(nc1);
-        assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        if (isAtLeastR()) {
+            assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        }
 
         // Because they now have the same SSID, the following call should not throw
         nc2.combineCapabilities(nc1);
@@ -601,12 +603,16 @@
         // from nc2.
         assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
         assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
-        assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        if (isAtLeastR()) {
+            assertTrue(TEST_SSID.equals(nc2.getSsid()));
+        }
 
         nc1.setSSID(DIFFERENT_TEST_SSID);
         nc2.set(nc1);
         assertEquals(nc1, nc2);
-        assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
+        if (isAtLeastR()) {
+            assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid()));
+        }
 
         nc1.setUids(uidRange(10, 13));
         nc2.set(nc1);  // Overwrites, as opposed to combineCapabilities
diff --git a/tools/stats_log_api_gen/.clang-format b/tools/stats_log_api_gen/.clang-format
new file mode 100644
index 0000000..cead3a0
--- /dev/null
+++ b/tools/stats_log_api_gen/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: false
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+  - Regex:    '^"Log\.h"'
+    Priority:    -1
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 47eb63e..bf39093 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -15,11 +15,13 @@
  */
 
 #include "Collation.h"
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
 
 #include <stdio.h>
+
 #include <map>
 
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
@@ -32,55 +34,47 @@
 
 const bool dbg = false;
 
-
 //
 // AtomDecl class
 //
 
-AtomDecl::AtomDecl()
-    :code(0),
-     name()
-{
+AtomDecl::AtomDecl() : code(0), name() {
 }
 
-AtomDecl::AtomDecl(const AtomDecl &that)
-      : code(that.code),
-        name(that.name),
-        message(that.message),
-        fields(that.fields),
-        fieldNumberToAnnotations(that.fieldNumberToAnnotations),
-        primaryFields(that.primaryFields),
-        exclusiveField(that.exclusiveField),
-        defaultState(that.defaultState),
-        resetState(that.resetState),
-        nested(that.nested),
-        uidField(that.uidField),
-        whitelisted(that.whitelisted) {}
-
-AtomDecl::AtomDecl(int c, const string& n, const string& m)
-    :code(c),
-     name(n),
-     message(m)
-{
+AtomDecl::AtomDecl(const AtomDecl& that)
+    : code(that.code),
+      name(that.name),
+      message(that.message),
+      fields(that.fields),
+      fieldNumberToAnnotations(that.fieldNumberToAnnotations),
+      primaryFields(that.primaryFields),
+      exclusiveField(that.exclusiveField),
+      defaultState(that.defaultState),
+      resetState(that.resetState),
+      nested(that.nested),
+      uidField(that.uidField),
+      whitelisted(that.whitelisted),
+      truncateTimestamp(that.truncateTimestamp) {
 }
 
-AtomDecl::~AtomDecl()
-{
+AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) {
 }
 
+AtomDecl::~AtomDecl() {
+}
 
 /**
- * Print an error message for a FieldDescriptor, including the file name and line number.
+ * Print an error message for a FieldDescriptor, including the file name and
+ * line number.
  */
-static void
-print_error(const FieldDescriptor* field, const char* format, ...)
-{
+static void print_error(const FieldDescriptor* field, const char* format, ...) {
     const Descriptor* message = field->containing_type();
     const FileDescriptor* file = message->file();
 
     SourceLocation loc;
     if (field->GetSourceLocation(&loc)) {
-        // TODO: this will work if we can figure out how to pass --include_source_info to protoc
+        // TODO: this will work if we can figure out how to pass
+        // --include_source_info to protoc
         fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
     } else {
         fprintf(stderr, "%s: ", file->name().c_str());
@@ -88,15 +82,13 @@
     va_list args;
     va_start(args, format);
     vfprintf(stderr, format, args);
-    va_end (args);
+    va_end(args);
 }
 
 /**
  * Convert a protobuf type into a java type.
  */
-static java_type_t
-java_type(const FieldDescriptor* field)
-{
+static java_type_t java_type(const FieldDescriptor* field) {
     int protoType = field->type();
     switch (protoType) {
         case FieldDescriptor::TYPE_DOUBLE:
@@ -121,12 +113,10 @@
             return JAVA_TYPE_UNKNOWN;
         case FieldDescriptor::TYPE_MESSAGE:
             // TODO: not the final package name
-            if (field->message_type()->full_name() ==
-                "android.os.statsd.AttributionNode") {
-              return JAVA_TYPE_ATTRIBUTION_CHAIN;
-            } else if (field->message_type()->full_name() ==
-                       "android.os.statsd.KeyValuePair") {
-              return JAVA_TYPE_KEY_VALUE_PAIR;
+            if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
+                return JAVA_TYPE_ATTRIBUTION_CHAIN;
+            } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
+                return JAVA_TYPE_KEY_VALUE_PAIR;
             } else if (field->options().GetExtension(os::statsd::log_mode) ==
                        os::statsd::LogMode::MODE_BYTES) {
                 return JAVA_TYPE_BYTE_ARRAY;
@@ -155,307 +145,298 @@
 /**
  * Gather the enums info.
  */
-void collate_enums(const EnumDescriptor &enumDescriptor, AtomField *atomField) {
+void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
     for (int i = 0; i < enumDescriptor.value_count(); i++) {
         atomField->enumValues[enumDescriptor.value(i)->number()] =
-            enumDescriptor.value(i)->name().c_str();
+                enumDescriptor.value(i)->name().c_str();
     }
 }
 
 static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
-        const int annotationId, const AnnotationType annotationType,
-        const AnnotationValue annotationValue) {
+                                    const int annotationId, const AnnotationType annotationType,
+                                    const AnnotationValue annotationValue) {
     if (dbg) {
-        printf("   Adding annotation to %s: [%d] = {id: %d, type: %d}\n",
-                atomDecl->name.c_str(), fieldNumber, annotationId, annotationType);
+        printf("   Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
+               fieldNumber, annotationId, annotationType);
     }
-    atomDecl->fieldNumberToAnnotations[fieldNumber].insert(make_shared<Annotation>(
-                annotationId, atomDecl->code, annotationType, annotationValue));
+    atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
+            make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
 }
 
-/**
- * Gather the info about an atom proto.
- */
-int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
-                 vector<java_type_t> *signature) {
-
-  int errorCount = 0;
-
-  // Build a sorted list of the fields. Descriptor has them in source file
-  // order.
-  map<int, const FieldDescriptor *> fields;
-  for (int j = 0; j < atom->field_count(); j++) {
-    const FieldDescriptor *field = atom->field(j);
-    fields[field->number()] = field;
-  }
-
-  // Check that the parameters start at 1 and go up sequentially.
-  int expectedNumber = 1;
-  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
-       it != fields.end(); it++) {
-    const int number = it->first;
-    const FieldDescriptor *field = it->second;
-    if (number != expectedNumber) {
-      print_error(field,
-                  "Fields must be numbered consecutively starting at 1:"
-                  " '%s' is %d but should be %d\n",
-                  field->name().c_str(), number, expectedNumber);
-      errorCount++;
-      expectedNumber = number;
-      continue;
-    }
-    expectedNumber++;
-  }
-
-  // Check that only allowed types are present. Remove any invalid ones.
-  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
-       it != fields.end(); it++) {
-    const FieldDescriptor *field = it->second;
-    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
-                         os::statsd::LogMode::MODE_BYTES;
-
-    java_type_t javaType = java_type(field);
-
-    if (javaType == JAVA_TYPE_UNKNOWN) {
-      print_error(field, "Unkown type for field: %s\n", field->name().c_str());
-      errorCount++;
-      continue;
-    } else if (javaType == JAVA_TYPE_OBJECT &&
-               atomDecl->code < PULL_ATOM_START_ID) {
-        // Allow attribution chain, but only at position 1.
-        print_error(field,
-                    "Message type not allowed for field in pushed atoms: %s\n",
-                    field->name().c_str());
-        errorCount++;
-        continue;
-    } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
-        print_error(field, "Raw bytes type not allowed for field: %s\n",
-                    field->name().c_str());
-        errorCount++;
-        continue;
-    }
-
-    if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
-        print_error(field, "Cannot mark field %s as bytes.\n",
-                    field->name().c_str());
-        errorCount++;
-        continue;
-    }
-
-    // Doubles are not supported yet.
-    if (javaType == JAVA_TYPE_DOUBLE) {
-        print_error(field, "Doubles are not supported in atoms. Please change field %s to float\n",
-                    field->name().c_str());
-        errorCount++;
-        continue;
-    }
-
-    if (field->is_repeated() &&
-        !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
-        print_error(field,
-                    "Repeated fields are not supported in atoms. Please make field %s not "
-                    "repeated.\n",
-                    field->name().c_str());
-        errorCount++;
-        continue;
-    }
-  }
-
-  // Check that if there's an attribution chain, it's at position 1.
-  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
-       it != fields.end(); it++) {
-    int number = it->first;
-    if (number != 1) {
-      const FieldDescriptor *field = it->second;
-      java_type_t javaType = java_type(field);
-      if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-        print_error(
-            field,
-            "AttributionChain fields must have field id 1, in message: '%s'\n",
-            atom->name().c_str());
-        errorCount++;
-      }
-    }
-  }
-
-  // Build the type signature and the atom data.
-  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
-       it != fields.end(); it++) {
-    const FieldDescriptor *field = it->second;
-    java_type_t javaType = java_type(field);
-    bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
-                         os::statsd::LogMode::MODE_BYTES;
-
-    AtomField atField(field->name(), javaType);
-    // Generate signature for pushed atoms
-    if (atomDecl->code < PULL_ATOM_START_ID) {
-      if (javaType == JAVA_TYPE_ENUM) {
-        // All enums are treated as ints when it comes to function signatures.
-        signature->push_back(JAVA_TYPE_INT);
-      } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
-          signature->push_back(JAVA_TYPE_BYTE_ARRAY);
-      } else {
-          signature->push_back(javaType);
-      }
-    }
-    if (javaType == JAVA_TYPE_ENUM) {
-      // All enums are treated as ints when it comes to function signatures.
-      collate_enums(*field->enum_type(), &atField);
-    }
-    atomDecl->fields.push_back(atField);
+static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
+                                     const int fieldNumber, const java_type_t& javaType) {
+    int errorCount = 0;
 
     if (field->options().HasExtension(os::statsd::state_field_option)) {
         const int option = field->options().GetExtension(os::statsd::state_field_option).option();
         if (option != STATE_OPTION_UNSET) {
-            addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_OPTION,
-                    ANNOTATION_TYPE_INT, AnnotationValue(option));
+            addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_OPTION,
+                                    ANNOTATION_TYPE_INT, AnnotationValue(option));
         }
 
         if (option == STATE_OPTION_PRIMARY) {
-            if (javaType == JAVA_TYPE_UNKNOWN ||
-                    javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
-                    javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
-                print_error(
-                    field,
-                    "Invalid primary state field: '%s'\n",
-                    atom->name().c_str());
+            if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+                javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+                print_error(field, "Invalid primary state field: '%s'\n",
+                            atomDecl->message.c_str());
                 errorCount++;
-                continue;
             }
-            atomDecl->primaryFields.push_back(it->first);
-
+            atomDecl->primaryFields.push_back(fieldNumber);
         }
 
         if (option == STATE_OPTION_PRIMARY_FIELD_FIRST_UID) {
             if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
-                print_error(
-                    field,
-                    "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: '%s'\n",
-                    atom->name().c_str());
+                print_error(field,
+                            "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
+                            "'%s'\n",
+                            atomDecl->message.c_str());
                 errorCount++;
-                continue;
             } else {
                 atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
             }
         }
 
         if (option == STATE_OPTION_EXCLUSIVE) {
-            if (javaType == JAVA_TYPE_UNKNOWN ||
-                    javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
-                    javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
-                print_error(
-                    field,
-                    "Invalid exclusive state field: '%s'\n",
-                    atom->name().c_str());
+            if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
+                javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
+                print_error(field, "Invalid exclusive state field: '%s'\n",
+                            atomDecl->message.c_str());
                 errorCount++;
-                continue;
             }
 
             if (atomDecl->exclusiveField == 0) {
-                atomDecl->exclusiveField = it->first;
+                atomDecl->exclusiveField = fieldNumber;
             } else {
-                print_error(
-                    field,
-                    "Cannot have more than one exclusive state field in an atom: '%s'\n",
-                    atom->name().c_str());
+                print_error(field,
+                            "Cannot have more than one exclusive state field in an "
+                            "atom: '%s'\n",
+                            atomDecl->message.c_str());
                 errorCount++;
-                continue;
             }
 
             if (field->options()
                         .GetExtension(os::statsd::state_field_option)
                         .has_default_state_value()) {
-                const int defaultState =
-                        field->options().GetExtension(os::statsd::state_field_option)
-                        .default_state_value();
+                const int defaultState = field->options()
+                                                 .GetExtension(os::statsd::state_field_option)
+                                                 .default_state_value();
                 atomDecl->defaultState = defaultState;
 
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_DEFAULT_STATE,
-                        ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
+                addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
+                                        ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
             }
 
-            if (field->options().GetExtension(os::statsd::state_field_option)
-                    .has_reset_state_value()) {
-                const int resetState = field->options()
+            if (field->options()
                         .GetExtension(os::statsd::state_field_option)
-                        .reset_state_value();
+                        .has_reset_state_value()) {
+                const int resetState = field->options()
+                                               .GetExtension(os::statsd::state_field_option)
+                                               .reset_state_value();
 
                 atomDecl->resetState = resetState;
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_RESET_STATE,
-                        ANNOTATION_TYPE_INT, AnnotationValue(resetState));
+                addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_RESET_STATE,
+                                        ANNOTATION_TYPE_INT, AnnotationValue(resetState));
             }
 
-            if (field->options().GetExtension(os::statsd::state_field_option)
-                    .has_nested()) {
+            if (field->options().GetExtension(os::statsd::state_field_option).has_nested()) {
                 const bool nested =
                         field->options().GetExtension(os::statsd::state_field_option).nested();
                 atomDecl->nested = nested;
 
-                addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_STATE_NESTED,
-                        ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
+                addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
+                                        ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
             }
         }
-
     }
+
     if (field->options().GetExtension(os::statsd::is_uid) == true) {
         if (javaType != JAVA_TYPE_INT) {
-            print_error(
-                field,
-                "is_uid annotation can only be applied to int32 fields: '%s'\n",
-                atom->name().c_str());
+            print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
+                        atomDecl->message.c_str());
             errorCount++;
-            continue;
         }
 
         if (atomDecl->uidField == 0) {
-            atomDecl->uidField = it->first;
+            atomDecl->uidField = fieldNumber;
 
-            addAnnotationToAtomDecl(atomDecl, signature->size(), ANNOTATION_ID_IS_UID,
-                    ANNOTATION_TYPE_BOOL, AnnotationValue(true));
+            addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
+                                    ANNOTATION_TYPE_BOOL, AnnotationValue(true));
         } else {
-            print_error(
-                field,
-                "Cannot have more than one field in an atom with is_uid annotation: '%s'\n",
-                atom->name().c_str());
+            print_error(field,
+                        "Cannot have more than one field in an atom with is_uid "
+                        "annotation: '%s'\n",
+                        atomDecl->message.c_str());
+            errorCount++;
+        }
+    }
+
+    return errorCount;
+}
+
+/**
+ * Gather the info about an atom proto.
+ */
+int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
+    int errorCount = 0;
+
+    // Build a sorted list of the fields. Descriptor has them in source file
+    // order.
+    map<int, const FieldDescriptor*> fields;
+    for (int j = 0; j < atom->field_count(); j++) {
+        const FieldDescriptor* field = atom->field(j);
+        fields[field->number()] = field;
+    }
+
+    // Check that the parameters start at 1 and go up sequentially.
+    int expectedNumber = 1;
+    for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+         it++) {
+        const int number = it->first;
+        const FieldDescriptor* field = it->second;
+        if (number != expectedNumber) {
+            print_error(field,
+                        "Fields must be numbered consecutively starting at 1:"
+                        " '%s' is %d but should be %d\n",
+                        field->name().c_str(), number, expectedNumber);
+            errorCount++;
+            expectedNumber = number;
+            continue;
+        }
+        expectedNumber++;
+    }
+
+    // Check that only allowed types are present. Remove any invalid ones.
+    for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+         it++) {
+        const FieldDescriptor* field = it->second;
+        bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                             os::statsd::LogMode::MODE_BYTES;
+
+        java_type_t javaType = java_type(field);
+
+        if (javaType == JAVA_TYPE_UNKNOWN) {
+            print_error(field, "Unknown type for field: %s\n", field->name().c_str());
+            errorCount++;
+            continue;
+        } else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
+            // Allow attribution chain, but only at position 1.
+            print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
+                        field->name().c_str());
+            errorCount++;
+            continue;
+        } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
+            print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
+            errorCount++;
+            continue;
+        }
+
+        if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
+            print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
+            errorCount++;
+            continue;
+        }
+
+        // Doubles are not supported yet.
+        if (javaType == JAVA_TYPE_DOUBLE) {
+            print_error(field,
+                        "Doubles are not supported in atoms. Please change field %s "
+                        "to float\n",
+                        field->name().c_str());
+            errorCount++;
+            continue;
+        }
+
+        if (field->is_repeated() &&
+            !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
+            print_error(field,
+                        "Repeated fields are not supported in atoms. Please make "
+                        "field %s not "
+                        "repeated.\n",
+                        field->name().c_str());
             errorCount++;
             continue;
         }
     }
-  }
 
-  return errorCount;
+    // Check that if there's an attribution chain, it's at position 1.
+    for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+         it++) {
+        int number = it->first;
+        if (number != 1) {
+            const FieldDescriptor* field = it->second;
+            java_type_t javaType = java_type(field);
+            if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+                print_error(field,
+                            "AttributionChain fields must have field id 1, in message: '%s'\n",
+                            atom->name().c_str());
+                errorCount++;
+            }
+        }
+    }
+
+    // Build the type signature and the atom data.
+    for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+         it++) {
+        const FieldDescriptor* field = it->second;
+        java_type_t javaType = java_type(field);
+        bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
+                             os::statsd::LogMode::MODE_BYTES;
+
+        AtomField atField(field->name(), javaType);
+
+        if (javaType == JAVA_TYPE_ENUM) {
+            // All enums are treated as ints when it comes to function signatures.
+            collate_enums(*field->enum_type(), &atField);
+        }
+
+        // Generate signature for pushed atoms
+        if (atomDecl->code < PULL_ATOM_START_ID) {
+            if (javaType == JAVA_TYPE_ENUM) {
+                // All enums are treated as ints when it comes to function signatures.
+                signature->push_back(JAVA_TYPE_INT);
+            } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
+                signature->push_back(JAVA_TYPE_BYTE_ARRAY);
+            } else {
+                signature->push_back(javaType);
+            }
+        }
+
+        atomDecl->fields.push_back(atField);
+
+        errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
+    }
+
+    return errorCount;
 }
 
-// This function flattens the fields of the AttributionNode proto in an Atom proto and generates
-// the corresponding atom decl and signature.
-bool get_non_chained_node(const Descriptor *atom, AtomDecl *atomDecl,
-                          vector<java_type_t> *signature) {
+// This function flattens the fields of the AttributionNode proto in an Atom
+// proto and generates the corresponding atom decl and signature.
+bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
+                          vector<java_type_t>* signature) {
     // Build a sorted list of the fields. Descriptor has them in source file
     // order.
-    map<int, const FieldDescriptor *> fields;
+    map<int, const FieldDescriptor*> fields;
     for (int j = 0; j < atom->field_count(); j++) {
-        const FieldDescriptor *field = atom->field(j);
+        const FieldDescriptor* field = atom->field(j);
         fields[field->number()] = field;
     }
 
     AtomDecl attributionDecl;
     vector<java_type_t> attributionSignature;
-    collate_atom(android::os::statsd::AttributionNode::descriptor(),
-                 &attributionDecl, &attributionSignature);
+    collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
+                 &attributionSignature);
 
     // Build the type signature and the atom data.
     bool has_attribution_node = false;
-    for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
-        it != fields.end(); it++) {
-        const FieldDescriptor *field = it->second;
+    for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
+         it++) {
+        const FieldDescriptor* field = it->second;
         java_type_t javaType = java_type(field);
         if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-            atomDecl->fields.insert(
-                atomDecl->fields.end(),
-                attributionDecl.fields.begin(), attributionDecl.fields.end());
-            signature->insert(
-                signature->end(),
-                attributionSignature.begin(), attributionSignature.end());
+            atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
+                                    attributionDecl.fields.end());
+            signature->insert(signature->end(), attributionSignature.begin(),
+                              attributionSignature.end());
             has_attribution_node = true;
 
         } else {
@@ -473,118 +454,129 @@
     return has_attribution_node;
 }
 
-static void populateFieldNumberToAnnotations(
-        const AtomDecl& atomDecl,
-        FieldNumberToAnnotations* fieldNumberToAnnotations) {
+static void populateFieldNumberToAnnotations(const AtomDecl& atomDecl,
+                                             FieldNumberToAnnotations* fieldNumberToAnnotations) {
     for (FieldNumberToAnnotations::const_iterator it = atomDecl.fieldNumberToAnnotations.begin();
-            it != atomDecl.fieldNumberToAnnotations.end(); it++) {
+         it != atomDecl.fieldNumberToAnnotations.end(); it++) {
         const int fieldNumber = it->first;
         const set<shared_ptr<Annotation>>& insertAnnotationsSource = it->second;
         set<shared_ptr<Annotation>>& insertAnnotationsTarget =
                 (*fieldNumberToAnnotations)[fieldNumber];
-        insertAnnotationsTarget.insert(
-                insertAnnotationsSource.begin(),
-                insertAnnotationsSource.end());
+        insertAnnotationsTarget.insert(insertAnnotationsSource.begin(),
+                                       insertAnnotationsSource.end());
     }
 }
 
 /**
  * Gather the info about the atoms.
  */
-int collate_atoms(const Descriptor *descriptor, const string& moduleName, Atoms *atoms) {
-  int errorCount = 0;
+int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
+    int errorCount = 0;
 
-  int maxPushedAtomId = 2;
-  for (int i = 0; i < descriptor->field_count(); i++) {
-    const FieldDescriptor *atomField = descriptor->field(i);
+    int maxPushedAtomId = 2;
+    for (int i = 0; i < descriptor->field_count(); i++) {
+        const FieldDescriptor* atomField = descriptor->field(i);
 
-    if (moduleName != DEFAULT_MODULE_NAME) {
-        const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
-        int j;
-        for (j = 0; j < moduleCount; ++j) {
-            const string atomModuleName = atomField->options().GetExtension(os::statsd::module, j);
-            if (atomModuleName == moduleName) {
-                break;
+        if (moduleName != DEFAULT_MODULE_NAME) {
+            const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
+            int j;
+            for (j = 0; j < moduleCount; ++j) {
+                const string atomModuleName =
+                        atomField->options().GetExtension(os::statsd::module, j);
+                if (atomModuleName == moduleName) {
+                    break;
+                }
+            }
+
+            // This atom is not in the module we're interested in; skip it.
+            if (moduleCount == j) {
+                if (dbg) {
+                    printf("   Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
+                }
+                continue;
             }
         }
 
-        // This atom is not in the module we're interested in; skip it.
-        if (moduleCount == j) {
-            if (dbg) {
-              printf("   Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
-            }
+        if (dbg) {
+            printf("   %s (%d)\n", atomField->name().c_str(), atomField->number());
+        }
+
+        // StatsEvent only has one oneof, which contains only messages. Don't allow
+        // other types.
+        if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
+            print_error(atomField,
+                        "Bad type for atom. StatsEvent can only have message type "
+                        "fields: %s\n",
+                        atomField->name().c_str());
+            errorCount++;
             continue;
         }
+
+        const Descriptor* atom = atomField->message_type();
+        AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+
+        if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
+            atomDecl.whitelisted = true;
+            if (dbg) {
+                printf("%s is whitelisted\n", atomField->name().c_str());
+            }
+        }
+
+        if (atomDecl.code < PULL_ATOM_START_ID &&
+            atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
+            addAnnotationToAtomDecl(&atomDecl, ATOM_ID_FIELD_NUMBER,
+                                    ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
+                                    AnnotationValue(true));
+            if (dbg) {
+                printf("%s can have timestamp truncated\n", atomField->name().c_str());
+            }
+        }
+
+        vector<java_type_t> signature;
+        errorCount += collate_atom(atom, &atomDecl, &signature);
+        if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
+            print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
+                        atomField->name().c_str());
+            errorCount++;
+            continue;
+        }
+
+        atoms->decls.insert(atomDecl);
+        FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
+        populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
+
+        AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
+        vector<java_type_t> nonChainedSignature;
+        if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
+            atoms->non_chained_decls.insert(nonChainedAtomDecl);
+            FieldNumberToAnnotations& fieldNumberToAnnotations =
+                    atoms->nonChainedSignatureInfoMap[nonChainedSignature];
+            populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
+        }
+
+        if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
+            maxPushedAtomId = atomDecl.code;
+        }
     }
 
+    atoms->maxPushedAtomId = maxPushedAtomId;
+
     if (dbg) {
-      printf("   %s (%d)\n", atomField->name().c_str(), atomField->number());
+        printf("signatures = [\n");
+        for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
+                     atoms->signatureInfoMap.begin();
+             it != atoms->signatureInfoMap.end(); it++) {
+            printf("   ");
+            for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
+                 jt++) {
+                printf(" %d", (int)*jt);
+            }
+            printf("\n");
+        }
+        printf("]\n");
     }
 
-    // StatsEvent only has one oneof, which contains only messages. Don't allow
-    // other types.
-    if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
-      print_error(atomField,
-                  "Bad type for atom. StatsEvent can only have message type "
-                  "fields: %s\n",
-                  atomField->name().c_str());
-      errorCount++;
-      continue;
-    }
-
-    const Descriptor *atom = atomField->message_type();
-    AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
-
-    if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
-        atomDecl.whitelisted = true;
-    }
-
-    vector<java_type_t> signature;
-    errorCount += collate_atom(atom, &atomDecl, &signature);
-    if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
-        print_error(atomField,
-                  "Cannot have a primary field without an exclusive field: %s\n",
-                  atomField->name().c_str());
-        errorCount++;
-        continue;
-    }
-
-    atoms->decls.insert(atomDecl);
-    FieldNumberToAnnotations& fieldNumberToAnnotations = atoms->signatureInfoMap[signature];
-    populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
-
-    AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
-    vector<java_type_t> nonChainedSignature;
-    if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
-        atoms->non_chained_decls.insert(nonChainedAtomDecl);
-        FieldNumberToAnnotations& fieldNumberToAnnotations =
-                atoms->nonChainedSignatureInfoMap[nonChainedSignature];
-        populateFieldNumberToAnnotations(atomDecl, &fieldNumberToAnnotations);
-    }
-
-    if (atomDecl.code < PULL_ATOM_START_ID && atomDecl.code > maxPushedAtomId) {
-        maxPushedAtomId = atomDecl.code;
-    }
-  }
-
-  atoms->maxPushedAtomId = maxPushedAtomId;
-
-  if (dbg) {
-    printf("signatures = [\n");
-    for (map<vector<java_type_t>, FieldNumberToAnnotations>::const_iterator it =
-             atoms->signatureInfoMap.begin();
-         it != atoms->signatureInfoMap.end(); it++) {
-      printf("   ");
-      for (vector<java_type_t>::const_iterator jt = it->first.begin();
-           jt != it->first.end(); jt++){
-        printf(" %d", (int)*jt);
-      }
-      printf("\n");
-    }
-    printf("]\n");
-  }
-
-  return errorCount;
+    return errorCount;
 }
 
 }  // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index c6dad1d..2aedb21 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -17,24 +17,24 @@
 #ifndef ANDROID_STATS_LOG_API_GEN_COLLATION_H
 #define ANDROID_STATS_LOG_API_GEN_COLLATION_H
 
-
 #include <google/protobuf/descriptor.h>
-#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
 
+#include <map>
 #include <set>
 #include <vector>
-#include <map>
+
+#include "frameworks/base/cmds/statsd/src/atom_field_options.pb.h"
 
 namespace android {
 namespace stats_log_api_gen {
 
+using google::protobuf::Descriptor;
+using google::protobuf::FieldDescriptor;
 using std::map;
 using std::set;
 using std::shared_ptr;
 using std::string;
 using std::vector;
-using google::protobuf::Descriptor;
-using google::protobuf::FieldDescriptor;
 
 const int PULL_ATOM_START_ID = 10000;
 
@@ -52,26 +52,28 @@
 const int STATE_OPTION_PRIMARY_FIELD_FIRST_UID = os::statsd::StateField::PRIMARY_FIELD_FIRST_UID;
 const int STATE_OPTION_PRIMARY = os::statsd::StateField::PRIMARY_FIELD;
 
+const int ATOM_ID_FIELD_NUMBER = -1;
+
 const string DEFAULT_MODULE_NAME = "DEFAULT";
 
 /**
  * The types for atom parameters.
  */
 typedef enum {
-  JAVA_TYPE_UNKNOWN = 0,
+    JAVA_TYPE_UNKNOWN = 0,
 
-  JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
-  JAVA_TYPE_BOOLEAN = 2,
-  JAVA_TYPE_INT = 3,
-  JAVA_TYPE_LONG = 4,
-  JAVA_TYPE_FLOAT = 5,
-  JAVA_TYPE_DOUBLE = 6,
-  JAVA_TYPE_STRING = 7,
-  JAVA_TYPE_ENUM = 8,
-  JAVA_TYPE_KEY_VALUE_PAIR = 9,
+    JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
+    JAVA_TYPE_BOOLEAN = 2,
+    JAVA_TYPE_INT = 3,
+    JAVA_TYPE_LONG = 4,
+    JAVA_TYPE_FLOAT = 5,
+    JAVA_TYPE_DOUBLE = 6,
+    JAVA_TYPE_STRING = 7,
+    JAVA_TYPE_ENUM = 8,
+    JAVA_TYPE_KEY_VALUE_PAIR = 9,
 
-  JAVA_TYPE_OBJECT = -1,
-  JAVA_TYPE_BYTE_ARRAY = -2,
+    JAVA_TYPE_OBJECT = -1,
+    JAVA_TYPE_BYTE_ARRAY = -2,
 } java_type_t;
 
 enum AnnotationType {
@@ -84,8 +86,10 @@
     int intValue;
     bool boolValue;
 
-    AnnotationValue(const int value): intValue(value) {}
-    AnnotationValue(const bool value): boolValue(value) {}
+    AnnotationValue(const int value) : intValue(value) {
+    }
+    AnnotationValue(const bool value) : boolValue(value) {
+    }
 };
 
 struct Annotation {
@@ -95,16 +99,18 @@
     AnnotationValue value;
 
     inline Annotation(unsigned char annotationId, int atomId, AnnotationType type,
-            AnnotationValue value):
-            annotationId(annotationId), atomId(atomId), type(type), value(value) {}
-    inline ~Annotation() {}
+                      AnnotationValue value)
+        : annotationId(annotationId), atomId(atomId), type(type), value(value) {
+    }
+    inline ~Annotation() {
+    }
 
     inline bool operator<(const Annotation& that) const {
         return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId;
     }
 };
 
-using FieldNumberToAnnotations =  map<int, set<shared_ptr<Annotation>>>;
+using FieldNumberToAnnotations = map<int, set<shared_ptr<Annotation>>>;
 
 /**
  * The name and type for an atom field.
@@ -113,16 +119,20 @@
     string name;
     java_type_t javaType;
 
-    // If the field is of type enum, the following map contains the list of enum values.
+    // If the field is of type enum, the following map contains the list of enum
+    // values.
     map<int /* numeric value */, string /* value name */> enumValues;
 
-    inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {}
-    inline AtomField(const AtomField& that) :name(that.name),
-                                             javaType(that.javaType),
-                                             enumValues(that.enumValues) {}
+    inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) {
+    }
+    inline AtomField(const AtomField& that)
+        : name(that.name), javaType(that.javaType), enumValues(that.enumValues) {
+    }
 
-    inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {}
-    inline ~AtomField() {}
+    inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) {
+    }
+    inline ~AtomField() {
+    }
 };
 
 /**
@@ -147,6 +157,8 @@
 
     bool whitelisted = false;
 
+    bool truncateTimestamp = false;
+
     AtomDecl();
     AtomDecl(const AtomDecl& that);
     AtomDecl(int code, const string& name, const string& message);
@@ -169,10 +181,9 @@
  * Gather the information about the atoms.  Returns the number of errors.
  */
 int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms);
-int collate_atom(const Descriptor *atom, AtomDecl *atomDecl, vector<java_type_t> *signature);
+int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
 
-
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
+#endif  // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/atoms_info_writer.cpp b/tools/stats_log_api_gen/atoms_info_writer.cpp
index 4f66f68..6944752 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.cpp
+++ b/tools/stats_log_api_gen/atoms_info_writer.cpp
@@ -15,12 +15,13 @@
  */
 
 #include "atoms_info_writer.h"
-#include "utils.h"
 
 #include <map>
 #include <set>
 #include <vector>
 
+#include "utils.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
@@ -42,32 +43,27 @@
             "  const static std::set<int> "
             "kTruncatingTimestampAtomBlackList;\n");
     fprintf(out, "  const static std::map<int, int> kAtomsWithUidField;\n");
-    fprintf(out,
-            "  const static std::set<int> kAtomsWithAttributionChain;\n");
+    fprintf(out, "  const static std::set<int> kAtomsWithAttributionChain;\n");
     fprintf(out,
             "  const static std::map<int, StateAtomFieldOptions> "
             "kStateAtomsFieldOptions;\n");
-    fprintf(out,
-            "  const static std::set<int> kWhitelistedAtoms;\n");
+    fprintf(out, "  const static std::set<int> kWhitelistedAtoms;\n");
     fprintf(out, "};\n");
     fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", atoms.maxPushedAtomId);
-
 }
 
 static void write_atoms_info_cpp_body(FILE* out, const Atoms& atoms) {
-    std::set<string> kTruncatingAtomNames = {
-            "mobile_radio_power_state_changed",
-            "audio_state_changed",
-            "call_state_changed",
-            "phone_signal_strength_changed",
-            "mobile_bytes_transfer_by_fg_bg",
-            "mobile_bytes_transfer"
-    };
+    std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
+                                             "audio_state_changed",
+                                             "call_state_changed",
+                                             "phone_signal_strength_changed",
+                                             "mobile_bytes_transfer_by_fg_bg",
+                                             "mobile_bytes_transfer"};
     fprintf(out,
             "const std::set<int> "
             "AtomsInfo::kTruncatingTimestampAtomBlackList = {\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         if (kTruncatingAtomNames.find(atom->name) != kTruncatingAtomNames.end()) {
             const string constant = make_constant_name(atom->name);
             fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
@@ -77,10 +73,9 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
-    fprintf(out,
-            "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
+    fprintf(out, "const std::set<int> AtomsInfo::kAtomsWithAttributionChain = {\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
              field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -94,10 +89,9 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
-    fprintf(out,
-            "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
+    fprintf(out, "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         if (atom->whitelisted) {
             const string constant = make_constant_name(atom->name);
             fprintf(out, "    %d, // %s\n", atom->code, constant.c_str());
@@ -109,8 +103,8 @@
 
     fprintf(out, "static std::map<int, int> getAtomUidField() {\n");
     fprintf(out, "    std::map<int, int> uidField;\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         if (atom->uidField == 0) {
             continue;
         }
@@ -118,8 +112,8 @@
                 "\n    // Adding uid field for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    uidField[%d /* %s */] = %d;\n",
-                atom->code, make_constant_name(atom->name).c_str(), atom->uidField);
+        fprintf(out, "    uidField[%d /* %s */] = %d;\n", atom->code,
+                make_constant_name(atom->name).c_str(), atom->uidField);
     }
 
     fprintf(out, "    return uidField;\n");
@@ -134,8 +128,8 @@
             "getStateAtomFieldOptions() {\n");
     fprintf(out, "    std::map<int, StateAtomFieldOptions> options;\n");
     fprintf(out, "    StateAtomFieldOptions* opt;\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-         atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         if (atom->primaryFields.size() == 0 && atom->exclusiveField == 0) {
             continue;
         }
@@ -143,8 +137,8 @@
                 "\n    // Adding primary and exclusive fields for atom "
                 "(%d)%s\n",
                 atom->code, atom->name.c_str());
-        fprintf(out, "    opt = &(options[%d /* %s */]);\n",
-                atom->code, make_constant_name(atom->name).c_str());
+        fprintf(out, "    opt = &(options[%d /* %s */]);\n", atom->code,
+                make_constant_name(atom->name).c_str());
         fprintf(out, "    opt->primaryFields.reserve(%lu);\n", atom->primaryFields.size());
         for (const auto& field : atom->primaryFields) {
             fprintf(out, "    opt->primaryFields.push_back(%d);\n", field);
@@ -174,7 +168,7 @@
             "getStateAtomFieldOptions();\n");
 }
 
-int write_atoms_info_header(FILE* out, const Atoms &atoms, const string& namespaceStr) {
+int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -195,8 +189,8 @@
     return 0;
 }
 
-int write_atoms_info_cpp(FILE *out, const Atoms &atoms, const string& namespaceStr,
-        const string& importHeader) {
+int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
+                         const string& importHeader) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/atoms_info_writer.h b/tools/stats_log_api_gen/atoms_info_writer.h
index d04e65a..ffe9e43 100644
--- a/tools/stats_log_api_gen/atoms_info_writer.h
+++ b/tools/stats_log_api_gen/atoms_info_writer.h
@@ -16,18 +16,18 @@
 
 #pragma once
 
-#include "Collation.h"
-
 #include <stdio.h>
 #include <string.h>
 
+#include "Collation.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
 using namespace std;
 
 int write_atoms_info_cpp(FILE* out, const Atoms& atoms, const string& namespaceStr,
-        const string& importHeader);
+                         const string& importHeader);
 
 int write_atoms_info_header(FILE* out, const Atoms& atoms, const string& namespaceStr);
 
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index 18508d2..5a22b5c 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "java_writer.h"
+
 #include "java_writer_q.h"
 #include "utils.h"
 
@@ -22,9 +23,8 @@
 namespace stats_log_api_gen {
 
 static int write_java_q_logger_class(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
-        const AtomDecl &attributionDecl) {
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+        const AtomDecl& attributionDecl) {
     fprintf(out, "\n");
     fprintf(out, "    // Write logging helper methods for statsd in Q and earlier.\n");
     fprintf(out, "    private static class QLogger {\n");
@@ -34,29 +34,27 @@
     // Print Q write methods.
     fprintf(out, "\n");
     fprintf(out, "        // Write methods.\n");
-    write_java_methods_q_schema(
-            out, signatureInfoMap, attributionDecl, "        ");
+    write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, "        ");
 
     fprintf(out, "    }\n");
     return 0;
 }
 
-static void write_annotations(
-        FILE* out, int argIndex,
-        const FieldNumberToAnnotations& fieldNumberToAnnotations) {
+static void write_annotations(FILE* out, int argIndex,
+                              const FieldNumberToAnnotations& fieldNumberToAnnotations) {
     auto it = fieldNumberToAnnotations.find(argIndex);
     if (it == fieldNumberToAnnotations.end()) {
         return;
     }
     const set<shared_ptr<Annotation>>& annotations = it->second;
-    for (auto& annotation: annotations) {
+    for (auto& annotation : annotations) {
         // TODO(b/151744250): Group annotations for same atoms.
         // TODO(b/151786433): Write atom constant name instead of atom id literal.
         fprintf(out, "        if (code == %d) {\n", annotation->atomId);
-        switch(annotation->type) {
+        switch (annotation->type) {
             case ANNOTATION_TYPE_INT:
-                // TODO(b/151776731): Check for reset state annotation and only include reset state
-                // when field value == default state annotation value.
+                // TODO(b/151776731): Check for reset state annotation and only include
+                // reset state when field value == default state annotation value.
                 // TODO(b/151786433): Write annotation constant name instead of
                 // annotation id literal.
                 fprintf(out, "            builder.addIntAnnotation((byte) %d, %d);\n",
@@ -66,8 +64,7 @@
                 // TODO(b/151786433): Write annotation constant name instead of
                 // annotation id literal.
                 fprintf(out, "            builder.addBooleanAnnotation((byte) %d, %s);\n",
-                        annotation->annotationId,
-                        annotation->value.boolValue ? "true" : "false");
+                        annotation->annotationId, annotation->value.boolValue ? "true" : "false");
                 break;
             default:
                 break;
@@ -77,24 +74,21 @@
 }
 
 static int write_java_methods(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
-        const AtomDecl &attributionDecl,
-        const bool supportQ
-        ) {
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+        const AtomDecl& attributionDecl, const bool supportQ) {
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
-            signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         // Print method signature.
         fprintf(out, "    public static void write(int code");
         const vector<java_type_t>& signature = signatureInfoMapIt->first;
         const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s[] %s",
-                        java_type_name(chainField.javaType), chainField.name.c_str());
+                    fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+                            chainField.name.c_str());
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -108,134 +102,134 @@
         // Print method body.
         string indent("");
         if (supportQ) {
-            // TODO(b/146235828): Use just SDK_INT check once it is incremented from Q.
+            // TODO(b/146235828): Use just SDK_INT check once it is incremented from
+            // Q.
             fprintf(out, "        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q\n");
-            fprintf(out, "                || (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q\n");
+            fprintf(out,
+                    "                || (Build.VERSION.SDK_INT == "
+                    "Build.VERSION_CODES.Q\n");
             fprintf(out, "                    && Build.VERSION.PREVIEW_SDK_INT > 0)) {\n");
             indent = "    ";
         }
 
         // Start StatsEvent.Builder.
-        fprintf(out, "%s        final StatsEvent.Builder builder = StatsEvent.newBuilder();\n",
+        fprintf(out,
+                "%s        final StatsEvent.Builder builder = "
+                "StatsEvent.newBuilder();\n",
                 indent.c_str());
 
         // Write atom code.
         fprintf(out, "%s        builder.setAtomId(code);\n", indent.c_str());
+        write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations);
 
         // Write the args.
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             switch (*arg) {
-            case JAVA_TYPE_BOOLEAN:
-                fprintf(out, "%s        builder.writeBoolean(arg%d);\n", indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_INT:
-            case JAVA_TYPE_ENUM:
-                fprintf(out, "%s        builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_FLOAT:
-                fprintf(out, "%s        builder.writeFloat(arg%d);\n", indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_LONG:
-                fprintf(out, "%s        builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_STRING:
-                fprintf(out, "%s        builder.writeString(arg%d);\n", indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_BYTE_ARRAY:
-                fprintf(out, "%s        builder.writeByteArray(null == arg%d ? new byte[0] : arg%d);\n",
-                        indent.c_str(), argIndex, argIndex);
-                break;
-            case JAVA_TYPE_ATTRIBUTION_CHAIN:
-            {
-                const char* uidName = attributionDecl.fields.front().name.c_str();
-                const char* tagName = attributionDecl.fields.back().name.c_str();
+                case JAVA_TYPE_BOOLEAN:
+                    fprintf(out, "%s        builder.writeBoolean(arg%d);\n", indent.c_str(),
+                            argIndex);
+                    break;
+                case JAVA_TYPE_INT:
+                case JAVA_TYPE_ENUM:
+                    fprintf(out, "%s        builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_FLOAT:
+                    fprintf(out, "%s        builder.writeFloat(arg%d);\n", indent.c_str(),
+                            argIndex);
+                    break;
+                case JAVA_TYPE_LONG:
+                    fprintf(out, "%s        builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_STRING:
+                    fprintf(out, "%s        builder.writeString(arg%d);\n", indent.c_str(),
+                            argIndex);
+                    break;
+                case JAVA_TYPE_BYTE_ARRAY:
+                    fprintf(out,
+                            "%s        builder.writeByteArray(null == arg%d ? new byte[0] : "
+                            "arg%d);\n",
+                            indent.c_str(), argIndex, argIndex);
+                    break;
+                case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+                    const char* uidName = attributionDecl.fields.front().name.c_str();
+                    const char* tagName = attributionDecl.fields.back().name.c_str();
 
-                fprintf(out, "%s        builder.writeAttributionChain(\n", indent.c_str());
-                fprintf(out, "%s                null == %s ? new int[0] : %s,\n",
-                        indent.c_str(), uidName, uidName);
-                fprintf(out, "%s                null == %s ? new String[0] : %s);\n",
-                        indent.c_str(), tagName, tagName);
-                break;
-            }
-            case JAVA_TYPE_KEY_VALUE_PAIR:
-                fprintf(out, "\n");
-                fprintf(out,
-                        "%s        // Write KeyValuePairs.\n", indent.c_str());
-                fprintf(out,
-                        "%s        final int count = valueMap.size();\n", indent.c_str());
-                fprintf(out,
-                        "%s        android.util.SparseIntArray intMap = null;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s        android.util.SparseLongArray longMap = null;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s        android.util.SparseArray<String> stringMap = null;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s        android.util.SparseArray<Float> floatMap = null;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s        for (int i = 0; i < count; i++) {\n", indent.c_str());
-                fprintf(out,
-                        "%s            final int key = valueMap.keyAt(i);\n", indent.c_str());
-                fprintf(out,
-                        "%s            final Object value = valueMap.valueAt(i);\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            if (value instanceof Integer) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                if (null == intMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                    intMap = new android.util.SparseIntArray();\n", indent.c_str());
-                fprintf(out,
-                        "%s                }\n", indent.c_str());
-                fprintf(out,
-                        "%s                intMap.put(key, (Integer) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s            } else if (value instanceof Long) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                if (null == longMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                    longMap = new android.util.SparseLongArray();\n", indent.c_str());
-                fprintf(out,
-                        "%s                }\n", indent.c_str());
-                fprintf(out,
-                        "%s                longMap.put(key, (Long) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s            } else if (value instanceof String) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                if (null == stringMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                    stringMap = new android.util.SparseArray<>();\n", indent.c_str());
-                fprintf(out,
-                        "%s                }\n", indent.c_str());
-                fprintf(out,
-                        "%s                stringMap.put(key, (String) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s            } else if (value instanceof Float) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                if (null == floatMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                    floatMap = new android.util.SparseArray<>();\n", indent.c_str());
-                fprintf(out,
-                        "%s                }\n", indent.c_str());
-                fprintf(out,
-                        "%s                floatMap.put(key, (Float) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s            }\n", indent.c_str());
-                fprintf(out,
-                        "%s        }\n", indent.c_str());
-                fprintf(out,
-                        "%s        builder.writeKeyValuePairs("
-                        "intMap, longMap, stringMap, floatMap);\n", indent.c_str());
-                break;
-            default:
-                // Unsupported types: OBJECT, DOUBLE.
-                fprintf(stderr, "Encountered unsupported type.");
-                return 1;
+                    fprintf(out, "%s        builder.writeAttributionChain(\n", indent.c_str());
+                    fprintf(out, "%s                null == %s ? new int[0] : %s,\n",
+                            indent.c_str(), uidName, uidName);
+                    fprintf(out, "%s                null == %s ? new String[0] : %s);\n",
+                            indent.c_str(), tagName, tagName);
+                    break;
+                }
+                case JAVA_TYPE_KEY_VALUE_PAIR:
+                    fprintf(out, "\n");
+                    fprintf(out, "%s        // Write KeyValuePairs.\n", indent.c_str());
+                    fprintf(out, "%s        final int count = valueMap.size();\n", indent.c_str());
+                    fprintf(out, "%s        android.util.SparseIntArray intMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s        android.util.SparseLongArray longMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s        android.util.SparseArray<String> stringMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s        android.util.SparseArray<Float> floatMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s        for (int i = 0; i < count; i++) {\n", indent.c_str());
+                    fprintf(out, "%s            final int key = valueMap.keyAt(i);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            final Object value = valueMap.valueAt(i);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            if (value instanceof Integer) {\n", indent.c_str());
+                    fprintf(out, "%s                if (null == intMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                    intMap = new "
+                            "android.util.SparseIntArray();\n",
+                            indent.c_str());
+                    fprintf(out, "%s                }\n", indent.c_str());
+                    fprintf(out, "%s                intMap.put(key, (Integer) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            } else if (value instanceof Long) {\n",
+                            indent.c_str());
+                    fprintf(out, "%s                if (null == longMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                    longMap = new "
+                            "android.util.SparseLongArray();\n",
+                            indent.c_str());
+                    fprintf(out, "%s                }\n", indent.c_str());
+                    fprintf(out, "%s                longMap.put(key, (Long) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            } else if (value instanceof String) {\n",
+                            indent.c_str());
+                    fprintf(out, "%s                if (null == stringMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                    stringMap = new "
+                            "android.util.SparseArray<>();\n",
+                            indent.c_str());
+                    fprintf(out, "%s                }\n", indent.c_str());
+                    fprintf(out, "%s                stringMap.put(key, (String) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            } else if (value instanceof Float) {\n",
+                            indent.c_str());
+                    fprintf(out, "%s                if (null == floatMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                    floatMap = new "
+                            "android.util.SparseArray<>();\n",
+                            indent.c_str());
+                    fprintf(out, "%s                }\n", indent.c_str());
+                    fprintf(out, "%s                floatMap.put(key, (Float) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s            }\n", indent.c_str());
+                    fprintf(out, "%s        }\n", indent.c_str());
+                    fprintf(out,
+                            "%s        builder.writeKeyValuePairs("
+                            "intMap, longMap, stringMap, floatMap);\n",
+                            indent.c_str());
+                    break;
+                default:
+                    // Unsupported types: OBJECT, DOUBLE.
+                    fprintf(stderr, "Encountered unsupported type.");
+                    return 1;
             }
             write_annotations(out, argIndex, fieldNumberToAnnotations);
             argIndex++;
@@ -251,7 +245,7 @@
             fprintf(out, "            QLogger.write(code");
             argIndex = 1;
             for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+                 arg != signature.end(); arg++) {
                 if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                     const char* uidName = attributionDecl.fields.front().name.c_str();
                     const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -266,20 +260,18 @@
                 argIndex++;
             }
             fprintf(out, ");\n");
-            fprintf(out, "        }\n"); // if
+            fprintf(out, "        }\n");  // if
         }
 
-        fprintf(out, "    }\n"); // method
+        fprintf(out, "    }\n");  // method
         fprintf(out, "\n");
     }
     return 0;
-
 }
 
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                                    const string& javaClass,
-                                    const string& javaPackage, const bool supportQ,
-                                    const bool supportWorkSource) {
+int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                         const string& javaClass, const string& javaPackage, const bool supportQ,
+                         const bool supportWorkSource) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -308,17 +300,14 @@
 
     // Print write methods.
     fprintf(out, "    // Write methods\n");
-    errors += write_java_methods(
-            out, atoms.signatureInfoMap, attributionDecl, supportQ);
-    errors += write_java_non_chained_methods(
-            out, atoms.nonChainedSignatureInfoMap);
+    errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+    errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
     if (supportWorkSource) {
         errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
     }
 
     if (supportQ) {
-        errors += write_java_q_logger_class(
-                out, atoms.signatureInfoMap, attributionDecl);
+        errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl);
     }
 
     fprintf(out, "}\n");
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 4e1365e..8b3b505 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -16,25 +16,23 @@
 
 #pragma once
 
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
 
 #include <map>
 #include <set>
 #include <vector>
 
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
 
 namespace android {
 namespace stats_log_api_gen {
 
 using namespace std;
 
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-                         const string& javaClass,
-                         const string& javaPackage, const bool supportQ,
+int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                         const string& javaClass, const string& javaPackage, const bool supportQ,
                          const bool supportWorkSource);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
-
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 329c25d..7d22583 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "java_writer_q.h"
+
 #include "utils.h"
 
 namespace android {
@@ -24,7 +25,8 @@
     fprintf(out, "%s// Payload limits.\n", indent.c_str());
     fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str());
     fprintf(out,
-            "%sprivate static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
+            "%sprivate static final int MAX_EVENT_PAYLOAD = "
+            "LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
             indent.c_str());
 
     // Value types. Must match with EventLog.java and log.h.
@@ -37,36 +39,36 @@
     fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str());
 
     // Size of each value type.
-    // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value.
+    // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for
+    // the value.
     fprintf(out, "\n");
     fprintf(out, "%s// Size of each value type.\n", indent.c_str());
     fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str());
     fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str());
     // Longs take 9 bytes, 1 for the type and 8 for the value.
     fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str());
-    // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length.
+    // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the
+    // length.
     fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str());
     fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str());
 }
 
 int write_java_methods_q_schema(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
-        const AtomDecl &attributionDecl,
-        const string& indent) {
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+        const AtomDecl& attributionDecl, const string& indent) {
     int requiredHelpers = 0;
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
-            signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         // Print method signature.
         vector<java_type_t> signature = signatureInfoMapIt->first;
         fprintf(out, "%spublic static void write(int code", indent.c_str());
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 for (auto chainField : attributionDecl.fields) {
-                    fprintf(out, ", %s[] %s",
-                        java_type_name(chainField.javaType), chainField.name.c_str());
+                    fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
+                            chainField.name.c_str());
                 }
             } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                 fprintf(out, ", android.util.SparseArray<Object> valueMap");
@@ -81,190 +83,174 @@
         fprintf(out, "%s    // Initial overhead of the list, timestamp, and atom tag.\n",
                 indent.c_str());
         fprintf(out,
-                "%s    int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n",
+                "%s    int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + "
+                "INT_TYPE_SIZE;\n",
                 indent.c_str());
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             switch (*arg) {
-            case JAVA_TYPE_BOOLEAN:
-            case JAVA_TYPE_INT:
-            case JAVA_TYPE_FLOAT:
-            case JAVA_TYPE_ENUM:
-                fprintf(out, "%s    needed += INT_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_LONG:
-                // Longs take 9 bytes, 1 for the type and 8 for the value.
-                fprintf(out, "%s    needed += LONG_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_STRING:
-                // Strings take 5 metadata bytes + length of byte encoded string.
-                fprintf(out, "%s    if (arg%d == null) {\n", indent.c_str(), argIndex);
-                fprintf(out, "%s        arg%d = \"\";\n", indent.c_str(), argIndex);
-                fprintf(out, "%s    }\n", indent.c_str());
-                fprintf(out,
-                        "%s    byte[] arg%dBytes = "
-                        "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
-                        indent.c_str(), argIndex, argIndex);
-                fprintf(out, "%s    needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
-                        indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_BYTE_ARRAY:
-                // Byte arrays take 5 metadata bytes + length of byte array.
-                fprintf(out, "%s    if (arg%d == null) {\n", indent.c_str(), argIndex);
-                fprintf(out, "%s        arg%d = new byte[0];\n", indent.c_str(), argIndex);
-                fprintf(out, "%s    }\n", indent.c_str());
-                fprintf(out, "%s    needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
-                        indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_ATTRIBUTION_CHAIN:
-            {
-                const char* uidName = attributionDecl.fields.front().name.c_str();
-                const char* tagName = attributionDecl.fields.back().name.c_str();
-                // Null checks on the params.
-                fprintf(out, "%s    if (%s == null) {\n", indent.c_str(), uidName);
-                fprintf(out, "%s        %s = new %s[0];\n", indent.c_str(), uidName,
-                        java_type_name(attributionDecl.fields.front().javaType));
-                fprintf(out, "%s    }\n", indent.c_str());
-                fprintf(out, "%s    if (%s == null) {\n", indent.c_str(), tagName);
-                fprintf(out, "%s        %s = new %s[0];\n", indent.c_str(), tagName,
-                        java_type_name(attributionDecl.fields.back().javaType));
-                fprintf(out, "%s    }\n", indent.c_str());
+                case JAVA_TYPE_BOOLEAN:
+                case JAVA_TYPE_INT:
+                case JAVA_TYPE_FLOAT:
+                case JAVA_TYPE_ENUM:
+                    fprintf(out, "%s    needed += INT_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_LONG:
+                    // Longs take 9 bytes, 1 for the type and 8 for the value.
+                    fprintf(out, "%s    needed += LONG_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_STRING:
+                    // Strings take 5 metadata bytes + length of byte encoded string.
+                    fprintf(out, "%s    if (arg%d == null) {\n", indent.c_str(), argIndex);
+                    fprintf(out, "%s        arg%d = \"\";\n", indent.c_str(), argIndex);
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out,
+                            "%s    byte[] arg%dBytes = "
+                            "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
+                            indent.c_str(), argIndex, argIndex);
+                    fprintf(out, "%s    needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+                            indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_BYTE_ARRAY:
+                    // Byte arrays take 5 metadata bytes + length of byte array.
+                    fprintf(out, "%s    if (arg%d == null) {\n", indent.c_str(), argIndex);
+                    fprintf(out, "%s        arg%d = new byte[0];\n", indent.c_str(), argIndex);
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out, "%s    needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
+                            indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+                    const char* uidName = attributionDecl.fields.front().name.c_str();
+                    const char* tagName = attributionDecl.fields.back().name.c_str();
+                    // Null checks on the params.
+                    fprintf(out, "%s    if (%s == null) {\n", indent.c_str(), uidName);
+                    fprintf(out, "%s        %s = new %s[0];\n", indent.c_str(), uidName,
+                            java_type_name(attributionDecl.fields.front().javaType));
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out, "%s    if (%s == null) {\n", indent.c_str(), tagName);
+                    fprintf(out, "%s        %s = new %s[0];\n", indent.c_str(), tagName,
+                            java_type_name(attributionDecl.fields.back().javaType));
+                    fprintf(out, "%s    }\n", indent.c_str());
 
-                // First check that the lengths of the uid and tag arrays are the same.
-                fprintf(out, "%s    if (%s.length != %s.length) {\n",
-                        indent.c_str(), uidName, tagName);
-                fprintf(out, "%s        return;\n", indent.c_str());
-                fprintf(out, "%s    }\n", indent.c_str());
-                fprintf(out, "%s    int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
-                fprintf(out, "%s    for (int i = 0; i < %s.length; i++) {\n",
-                        indent.c_str(), tagName);
-                fprintf(out, "%s        String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
-                        indent.c_str(), argIndex, tagName, tagName);
-                fprintf(out,
-                        "%s        int str%dlen = "
-                        "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
-                        indent.c_str(), argIndex, argIndex);
-                fprintf(out,
-                        "%s        attrSize += "
-                        "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n",
-                        indent.c_str(), argIndex);
-                fprintf(out, "%s    }\n", indent.c_str());
-                fprintf(out, "%s    needed += attrSize;\n", indent.c_str());
-                break;
-            }
-            case JAVA_TYPE_KEY_VALUE_PAIR:
-            {
-                fprintf(out,
-                        "%s    // Calculate bytes needed by Key Value Pairs.\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s    final int count = valueMap.size();\n", indent.c_str());
-                fprintf(out,
-                        "%s    android.util.SparseIntArray intMap = null;\n", indent.c_str());
-                fprintf(out,
-                        "%s    android.util.SparseLongArray longMap = null;\n", indent.c_str());
-                fprintf(out,
-                        "%s    android.util.SparseArray<String> stringMap = null;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s    android.util.SparseArray<Float> floatMap = null;\n", indent.c_str());
-                fprintf(out, "%s    int keyValuePairSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
-                fprintf(out,
-                        "%s    for (int i = 0; i < count; i++) {\n", indent.c_str());
-                fprintf(out,
-                        "%s        final int key = valueMap.keyAt(i);\n", indent.c_str());
-                fprintf(out,
-                        "%s        final Object value = valueMap.valueAt(i);\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s        if (value instanceof Integer) {\n", indent.c_str());
-                fprintf(out,
-                        "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s                    + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            if (null == intMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                intMap = new android.util.SparseIntArray();\n", indent.c_str());
-                fprintf(out,
-                        "%s            }\n", indent.c_str());
-                fprintf(out,
-                        "%s            intMap.put(key, (Integer) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s        } else if (value instanceof Long) {\n", indent.c_str());
-                fprintf(out,
-                        "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s                    + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            if (null == longMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                longMap = new android.util.SparseLongArray();\n", indent.c_str());
-                fprintf(out,
-                        "%s            }\n", indent.c_str());
-                fprintf(out,
-                        "%s            longMap.put(key, (Long) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s        } else if (value instanceof String) {\n", indent.c_str());
-                fprintf(out,
-                        "%s            final String str = (value == null) ? \"\" : "
-                        "(String) value;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            final int len = "
-                        "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            keyValuePairSize += LIST_TYPE_OVERHEAD + INT_TYPE_SIZE\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s                    + STRING_TYPE_OVERHEAD + len;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            if (null == stringMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                stringMap = new android.util.SparseArray<>();\n", indent.c_str());
-                fprintf(out,
-                        "%s            }\n", indent.c_str());
-                fprintf(out,
-                        "%s            stringMap.put(key, str);\n", indent.c_str());
-                fprintf(out,
-                        "%s        } else if (value instanceof Float) {\n", indent.c_str());
-                fprintf(out,
-                        "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s                    + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
-                        indent.c_str());
-                fprintf(out,
-                        "%s            if (null == floatMap) {\n", indent.c_str());
-                fprintf(out,
-                        "%s                floatMap = new android.util.SparseArray<>();\n", indent.c_str());
-                fprintf(out,
-                        "%s            }\n", indent.c_str());
-                fprintf(out,
-                        "%s            floatMap.put(key, (Float) value);\n", indent.c_str());
-                fprintf(out,
-                        "%s        }\n", indent.c_str());
-                fprintf(out,
-                        "%s    }\n", indent.c_str());
-                fprintf(out, "%s    needed += keyValuePairSize;\n", indent.c_str());
-                break;
-            }
-            default:
-                // Unsupported types: OBJECT, DOUBLE.
-                fprintf(stderr, "Module logging does not yet support Object and Double.\n");
-                return 1;
+                    // First check that the lengths of the uid and tag arrays are the
+                    // same.
+                    fprintf(out, "%s    if (%s.length != %s.length) {\n", indent.c_str(), uidName,
+                            tagName);
+                    fprintf(out, "%s        return;\n", indent.c_str());
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out, "%s    int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
+                    fprintf(out, "%s    for (int i = 0; i < %s.length; i++) {\n", indent.c_str(),
+                            tagName);
+                    fprintf(out, "%s        String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
+                            indent.c_str(), argIndex, tagName, tagName);
+                    fprintf(out,
+                            "%s        int str%dlen = "
+                            "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)."
+                            "length;\n",
+                            indent.c_str(), argIndex, argIndex);
+                    fprintf(out,
+                            "%s        attrSize += "
+                            "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + "
+                            "str%dlen;\n",
+                            indent.c_str(), argIndex);
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out, "%s    needed += attrSize;\n", indent.c_str());
+                    break;
+                }
+                case JAVA_TYPE_KEY_VALUE_PAIR: {
+                    fprintf(out, "%s    // Calculate bytes needed by Key Value Pairs.\n",
+                            indent.c_str());
+                    fprintf(out, "%s    final int count = valueMap.size();\n", indent.c_str());
+                    fprintf(out, "%s    android.util.SparseIntArray intMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s    android.util.SparseLongArray longMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s    android.util.SparseArray<String> stringMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s    android.util.SparseArray<Float> floatMap = null;\n",
+                            indent.c_str());
+                    fprintf(out, "%s    int keyValuePairSize = LIST_TYPE_OVERHEAD;\n",
+                            indent.c_str());
+                    fprintf(out, "%s    for (int i = 0; i < count; i++) {\n", indent.c_str());
+                    fprintf(out, "%s        final int key = valueMap.keyAt(i);\n", indent.c_str());
+                    fprintf(out, "%s        final Object value = valueMap.valueAt(i);\n",
+                            indent.c_str());
+                    fprintf(out, "%s        if (value instanceof Integer) {\n", indent.c_str());
+                    fprintf(out, "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+                            indent.c_str());
+                    fprintf(out, "%s                    + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
+                            indent.c_str());
+                    fprintf(out, "%s            if (null == intMap) {\n", indent.c_str());
+                    fprintf(out, "%s                intMap = new android.util.SparseIntArray();\n",
+                            indent.c_str());
+                    fprintf(out, "%s            }\n", indent.c_str());
+                    fprintf(out, "%s            intMap.put(key, (Integer) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s        } else if (value instanceof Long) {\n", indent.c_str());
+                    fprintf(out, "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+                            indent.c_str());
+                    fprintf(out, "%s                    + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
+                            indent.c_str());
+                    fprintf(out, "%s            if (null == longMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                longMap = new "
+                            "android.util.SparseLongArray();\n",
+                            indent.c_str());
+                    fprintf(out, "%s            }\n", indent.c_str());
+                    fprintf(out, "%s            longMap.put(key, (Long) value);\n", indent.c_str());
+                    fprintf(out, "%s        } else if (value instanceof String) {\n",
+                            indent.c_str());
+                    fprintf(out,
+                            "%s            final String str = (value == null) ? \"\" : "
+                            "(String) value;\n",
+                            indent.c_str());
+                    fprintf(out,
+                            "%s            final int len = "
+                            "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
+                            indent.c_str());
+                    fprintf(out,
+                            "%s            keyValuePairSize += LIST_TYPE_OVERHEAD + "
+                            "INT_TYPE_SIZE\n",
+                            indent.c_str());
+                    fprintf(out, "%s                    + STRING_TYPE_OVERHEAD + len;\n",
+                            indent.c_str());
+                    fprintf(out, "%s            if (null == stringMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                stringMap = new "
+                            "android.util.SparseArray<>();\n",
+                            indent.c_str());
+                    fprintf(out, "%s            }\n", indent.c_str());
+                    fprintf(out, "%s            stringMap.put(key, str);\n", indent.c_str());
+                    fprintf(out, "%s        } else if (value instanceof Float) {\n",
+                            indent.c_str());
+                    fprintf(out, "%s            keyValuePairSize += LIST_TYPE_OVERHEAD\n",
+                            indent.c_str());
+                    fprintf(out, "%s                    + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
+                            indent.c_str());
+                    fprintf(out, "%s            if (null == floatMap) {\n", indent.c_str());
+                    fprintf(out,
+                            "%s                floatMap = new "
+                            "android.util.SparseArray<>();\n",
+                            indent.c_str());
+                    fprintf(out, "%s            }\n", indent.c_str());
+                    fprintf(out, "%s            floatMap.put(key, (Float) value);\n",
+                            indent.c_str());
+                    fprintf(out, "%s        }\n", indent.c_str());
+                    fprintf(out, "%s    }\n", indent.c_str());
+                    fprintf(out, "%s    needed += keyValuePairSize;\n", indent.c_str());
+                    break;
+                }
+                default:
+                    // Unsupported types: OBJECT, DOUBLE.
+                    fprintf(stderr, "Module logging does not yet support Object and Double.\n");
+                    return 1;
             }
             argIndex++;
         }
 
-        // Now we have the size that is needed. Check for overflow and return if needed.
+        // Now we have the size that is needed. Check for overflow and return if
+        // needed.
         fprintf(out, "%s    if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str());
         fprintf(out, "%s        return;\n", indent.c_str());
         fprintf(out, "%s    }\n", indent.c_str());
@@ -279,7 +265,8 @@
         fprintf(out, "%s    pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
 
         // Write timestamp.
-        fprintf(out, "%s    long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n", indent.c_str());
+        fprintf(out, "%s    long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n",
+                indent.c_str());
         fprintf(out, "%s    buff[pos] = LONG_TYPE;\n", indent.c_str());
         fprintf(out, "%s    copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str());
         fprintf(out, "%s    pos += LONG_TYPE_SIZE;\n", indent.c_str());
@@ -291,77 +278,82 @@
 
         // Write the args.
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             switch (*arg) {
-            case JAVA_TYPE_BOOLEAN:
-                fprintf(out, "%s    buff[pos] = INT_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyInt(buff, pos + 1, arg%d? 1 : 0);\n",
-                        indent.c_str(), argIndex);
-                fprintf(out, "%s    pos += INT_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_INT:
-            case JAVA_TYPE_ENUM:
-                fprintf(out, "%s    buff[pos] = INT_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyInt(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
-                fprintf(out, "%s    pos += INT_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_FLOAT:
-                requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
-                fprintf(out, "%s    buff[pos] = FLOAT_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
-                fprintf(out, "%s    pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_LONG:
-                fprintf(out, "%s    buff[pos] = LONG_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyLong(buff, pos + 1, arg%d);\n", indent.c_str(), argIndex);
-                fprintf(out, "%s    pos += LONG_TYPE_SIZE;\n", indent.c_str());
-                break;
-            case JAVA_TYPE_STRING:
-                fprintf(out, "%s    buff[pos] = STRING_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyInt(buff, pos + 1, arg%dBytes.length);\n",
-                        indent.c_str(), argIndex);
-                fprintf(out, "%s    System.arraycopy("
-                        "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n",
-                        indent.c_str(), argIndex, argIndex);
-                fprintf(out, "%s    pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
-                        indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_BYTE_ARRAY:
-                fprintf(out, "%s    buff[pos] = STRING_TYPE;\n", indent.c_str());
-                fprintf(out, "%s    copyInt(buff, pos + 1, arg%d.length);\n",
-                        indent.c_str(), argIndex);
-                fprintf(out, "%s    System.arraycopy("
-                        "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
-                        indent.c_str(), argIndex, argIndex);
-                fprintf(out, "%s    pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
-                        indent.c_str(), argIndex);
-                break;
-            case JAVA_TYPE_ATTRIBUTION_CHAIN:
-            {
-                requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
-                const char* uidName = attributionDecl.fields.front().name.c_str();
-                const char* tagName = attributionDecl.fields.back().name.c_str();
+                case JAVA_TYPE_BOOLEAN:
+                    fprintf(out, "%s    buff[pos] = INT_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(),
+                            argIndex);
+                    fprintf(out, "%s    pos += INT_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_INT:
+                case JAVA_TYPE_ENUM:
+                    fprintf(out, "%s    buff[pos] = INT_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyInt(buff, pos + 1, arg%d);\n", indent.c_str(),
+                            argIndex);
+                    fprintf(out, "%s    pos += INT_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_FLOAT:
+                    requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+                    fprintf(out, "%s    buff[pos] = FLOAT_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(),
+                            argIndex);
+                    fprintf(out, "%s    pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_LONG:
+                    fprintf(out, "%s    buff[pos] = LONG_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyLong(buff, pos + 1, arg%d);\n", indent.c_str(),
+                            argIndex);
+                    fprintf(out, "%s    pos += LONG_TYPE_SIZE;\n", indent.c_str());
+                    break;
+                case JAVA_TYPE_STRING:
+                    fprintf(out, "%s    buff[pos] = STRING_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyInt(buff, pos + 1, arg%dBytes.length);\n",
+                            indent.c_str(), argIndex);
+                    fprintf(out,
+                            "%s    System.arraycopy("
+                            "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
+                            "arg%dBytes.length);\n",
+                            indent.c_str(), argIndex, argIndex);
+                    fprintf(out, "%s    pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+                            indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_BYTE_ARRAY:
+                    fprintf(out, "%s    buff[pos] = STRING_TYPE;\n", indent.c_str());
+                    fprintf(out, "%s    copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(),
+                            argIndex);
+                    fprintf(out,
+                            "%s    System.arraycopy("
+                            "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
+                            indent.c_str(), argIndex, argIndex);
+                    fprintf(out, "%s    pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
+                            indent.c_str(), argIndex);
+                    break;
+                case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+                    requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
+                    const char* uidName = attributionDecl.fields.front().name.c_str();
+                    const char* tagName = attributionDecl.fields.back().name.c_str();
 
-                fprintf(out, "%s    writeAttributionChain(buff, pos, %s, %s);\n", indent.c_str(),
-                        uidName, tagName);
-                fprintf(out, "%s    pos += attrSize;\n", indent.c_str());
-                break;
-            }
-            case JAVA_TYPE_KEY_VALUE_PAIR:
-                requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
-                requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
-                fprintf(out,
-                        "%s    writeKeyValuePairs(buff, pos, (byte) count, intMap, longMap, "
-                        "stringMap, floatMap);\n",
-                        indent.c_str());
-                fprintf(out, "%s    pos += keyValuePairSize;\n", indent.c_str());
-                break;
-            default:
-                // Unsupported types: OBJECT, DOUBLE.
-                fprintf(stderr,
-                        "Object and Double are not supported in module logging");
-                return 1;
+                    fprintf(out, "%s    writeAttributionChain(buff, pos, %s, %s);\n",
+                            indent.c_str(), uidName, tagName);
+                    fprintf(out, "%s    pos += attrSize;\n", indent.c_str());
+                    break;
+                }
+                case JAVA_TYPE_KEY_VALUE_PAIR:
+                    requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+                    requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
+                    fprintf(out,
+                            "%s    writeKeyValuePairs(buff, pos, (byte) count, intMap, "
+                            "longMap, "
+                            "stringMap, floatMap);\n",
+                            indent.c_str());
+                    fprintf(out, "%s    pos += keyValuePairSize;\n", indent.c_str());
+                    break;
+                default:
+                    // Unsupported types: OBJECT, DOUBLE.
+                    fprintf(stderr, "Object and Double are not supported in module logging");
+                    return 1;
             }
             argIndex++;
         }
@@ -376,11 +368,8 @@
     return 0;
 }
 
-void write_java_helpers_for_q_schema_methods(
-        FILE* out,
-        const AtomDecl &attributionDecl,
-        const int requiredHelpers,
-        const string& indent) {
+void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
+                                             const int requiredHelpers, const string& indent) {
     fprintf(out, "\n");
     fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str());
     fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n",
@@ -420,8 +409,7 @@
         fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
                 indent.c_str());
         for (auto chainField : attributionDecl.fields) {
-            fprintf(out, ", %s[] %s",
-                java_type_name(chainField.javaType), chainField.name.c_str());
+            fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
         }
         fprintf(out, ") {\n");
 
@@ -437,8 +425,8 @@
         fprintf(out, "%s    for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName);
         // Write the list begin.
         fprintf(out, "%s        buff[pos] = LIST_TYPE;\n", indent.c_str());
-        fprintf(out, "%s        buff[pos + 1] = %lu;\n",
-                indent.c_str(), attributionDecl.fields.size());
+        fprintf(out, "%s        buff[pos + 1] = %lu;\n", indent.c_str(),
+                attributionDecl.fields.size());
         fprintf(out, "%s        pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
 
         // Write the uid.
@@ -447,18 +435,20 @@
         fprintf(out, "%s        pos += INT_TYPE_SIZE;\n", indent.c_str());
 
         // Write the tag.
-        fprintf(out, "%s        String %sStr = (%s[i] == null) ? \"\" : %s[i];\n",
-                indent.c_str(), tagName, tagName, tagName);
-        fprintf(out, "%s        byte[] %sByte = "
+        fprintf(out, "%s        String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(),
+                tagName, tagName, tagName);
+        fprintf(out,
+                "%s        byte[] %sByte = "
                 "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
                 indent.c_str(), tagName, tagName);
         fprintf(out, "%s        buff[pos] = STRING_TYPE;\n", indent.c_str());
         fprintf(out, "%s        copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName);
-        fprintf(out, "%s        System.arraycopy("
+        fprintf(out,
+                "%s        System.arraycopy("
                 "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
                 indent.c_str(), tagName, tagName);
-        fprintf(out, "%s        pos += STRING_TYPE_OVERHEAD + %sByte.length;\n",
-                indent.c_str(), tagName);
+        fprintf(out, "%s        pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(),
+                tagName);
         fprintf(out, "%s    }\n", indent.c_str());
         fprintf(out, "%s}\n", indent.c_str());
         fprintf(out, "\n");
@@ -466,7 +456,8 @@
 
     if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
         fprintf(out,
-                "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, byte numPairs,\n",
+                "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, "
+                "byte numPairs,\n",
                 indent.c_str());
         fprintf(out, "%s        final android.util.SparseIntArray intMap,\n", indent.c_str());
         fprintf(out, "%s        final android.util.SparseLongArray longMap,\n", indent.c_str());
@@ -515,7 +506,9 @@
         fprintf(out, "%s    }\n", indent.c_str());
 
         // Write Strings.
-        fprintf(out, "%s    final int stringMapSize = null == stringMap ? 0 : stringMap.size();\n",
+        fprintf(out,
+                "%s    final int stringMapSize = null == stringMap ? 0 : "
+                "stringMap.size();\n",
                 indent.c_str());
         fprintf(out, "%s    for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
         fprintf(out, "%s        buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -523,7 +516,8 @@
         fprintf(out, "%s        pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
         fprintf(out, "%s        final int key = stringMap.keyAt(i);\n", indent.c_str());
         fprintf(out, "%s        final String value = stringMap.valueAt(i);\n", indent.c_str());
-        fprintf(out, "%s        final byte[] valueBytes = "
+        fprintf(out,
+                "%s        final byte[] valueBytes = "
                 "value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
                 indent.c_str());
         fprintf(out, "%s        buff[pos] = INT_TYPE;\n", indent.c_str());
@@ -531,15 +525,19 @@
         fprintf(out, "%s        pos += INT_TYPE_SIZE;\n", indent.c_str());
         fprintf(out, "%s        buff[pos] = STRING_TYPE;\n", indent.c_str());
         fprintf(out, "%s        copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str());
-        fprintf(out, "%s        System.arraycopy("
-                "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, valueBytes.length);\n",
+        fprintf(out,
+                "%s        System.arraycopy("
+                "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
+                "valueBytes.length);\n",
                 indent.c_str());
         fprintf(out, "%s        pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n",
                 indent.c_str());
         fprintf(out, "%s    }\n", indent.c_str());
 
         // Write floats.
-        fprintf(out, "%s    final int floatMapSize = null == floatMap ? 0 : floatMap.size();\n",
+        fprintf(out,
+                "%s    final int floatMapSize = null == floatMap ? 0 : "
+                "floatMap.size();\n",
                 indent.c_str());
         fprintf(out, "%s    for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
         fprintf(out, "%s        buff[pos] = LIST_TYPE;\n", indent.c_str());
@@ -559,12 +557,11 @@
     }
 }
 
-// This method is called in main.cpp to generate StatsLog for modules that's compatible with
-// Q at compile-time.
+// This method is called in main.cpp to generate StatsLog for modules that's
+// compatible with Q at compile-time.
 int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
-                                      const AtomDecl &attributionDecl,
-                                      const string& javaClass, const string& javaPackage,
-                                      const bool supportWorkSource) {
+                                      const AtomDecl& attributionDecl, const string& javaClass,
+                                      const string& javaPackage, const bool supportWorkSource) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -590,8 +587,7 @@
     int errors = 0;
     // Print write methods
     fprintf(out, "    // Write methods\n");
-    errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl,
-            "    ");
+    errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, "    ");
     errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
     if (supportWorkSource) {
         errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 0f33b6c..f1cfc44 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -16,14 +16,14 @@
 
 #pragma once
 
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
 
 #include <map>
 #include <set>
 #include <vector>
 
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
 
 namespace android {
 namespace stats_log_api_gen {
@@ -33,20 +33,15 @@
 void write_java_q_logging_constants(FILE* out, const string& indent);
 
 int write_java_methods_q_schema(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
-        const AtomDecl &attributionDecl,
-        const string& indent);
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
+        const AtomDecl& attributionDecl, const string& indent);
 
-void write_java_helpers_for_q_schema_methods(
-        FILE * out,
-        const AtomDecl &attributionDecl,
-        const int requiredHelpers,
-        const string& indent);
+void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
+                                             const int requiredHelpers, const string& indent);
 
 int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
-        const AtomDecl &attributionDecl, const string& javaClass,
-        const string& javaPackage, const bool supportWorkSource);
+                                      const AtomDecl& attributionDecl, const string& javaClass,
+                                      const string& javaPackage, const bool supportWorkSource);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 4f791a3..fda5736 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1,21 +1,20 @@
 
-#include "Collation.h"
-#include "atoms_info_writer.h"
-#include "java_writer.h"
-#include "java_writer_q.h"
-#include "native_writer.h"
-#include "utils.h"
-
-#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <map>
 #include <set>
 #include <vector>
 
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include "Collation.h"
+#include "atoms_info_writer.h"
+#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
+#include "java_writer.h"
+#include "java_writer_q.h"
+#include "native_writer.h"
+#include "utils.h"
 
 using namespace google::protobuf;
 using namespace std;
@@ -25,25 +24,34 @@
 
 using android::os::statsd::Atom;
 
-static void
-print_usage()
-{
+static void print_usage() {
     fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "OPTIONS\n");
     fprintf(stderr, "  --cpp FILENAME       the header file to output for write helpers\n");
     fprintf(stderr, "  --header FILENAME    the cpp file to output for write helpers\n");
     fprintf(stderr,
-            "  --atomsInfoCpp FILENAME       the header file to output for statsd metadata\n");
-    fprintf(stderr, "  --atomsInfoHeader FILENAME    the cpp file to output for statsd metadata\n");
+            "  --atomsInfoCpp FILENAME       the header file to output for "
+            "statsd metadata\n");
+    fprintf(stderr,
+            "  --atomsInfoHeader FILENAME    the cpp file to output for statsd "
+            "metadata\n");
     fprintf(stderr, "  --help               this message\n");
     fprintf(stderr, "  --java FILENAME      the java file to output\n");
     fprintf(stderr, "  --module NAME        optional, module name to generate outputs for\n");
-    fprintf(stderr, "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with module\n");
-    fprintf(stderr, "                                    comma separated namespace of the files\n");
-    fprintf(stderr,"  --importHeader NAME  required for cpp/jni to say which header to import "
+    fprintf(stderr,
+            "  --namespace COMMA,SEP,NAMESPACE   required for cpp/header with "
+            "module\n");
+    fprintf(stderr,
+            "                                    comma separated namespace of "
+            "the files\n");
+    fprintf(stderr,
+            "  --importHeader NAME  required for cpp/jni to say which header to "
+            "import "
             "for write helpers\n");
-    fprintf(stderr,"  --atomsInfoImportHeader NAME  required for cpp to say which header to import "
+    fprintf(stderr,
+            "  --atomsInfoImportHeader NAME  required for cpp to say which "
+            "header to import "
             "for statsd metadata\n");
     fprintf(stderr, "  --javaPackage PACKAGE             the package for the java file.\n");
     fprintf(stderr, "                                    required for java with module\n");
@@ -51,17 +59,18 @@
     fprintf(stderr, "                       Optional for Java with module.\n");
     fprintf(stderr, "                       Default is \"StatsLogInternal\"\n");
     fprintf(stderr, "  --supportQ           Include runtime support for Android Q.\n");
-    fprintf(stderr, "  --worksource         Include support for logging WorkSource objects.\n");
-    fprintf(stderr, "  --compileQ           Include compile-time support for Android Q "
+    fprintf(stderr,
+            "  --worksource         Include support for logging WorkSource "
+            "objects.\n");
+    fprintf(stderr,
+            "  --compileQ           Include compile-time support for Android Q "
             "(Java only).\n");
 }
 
 /**
  * Do the argument parsing and execute the tasks.
  */
-static int
-run(int argc, char const*const* argv)
-{
+static int run(int argc, char const* const* argv) {
     string cppFilename;
     string headerFilename;
     string javaFilename;
@@ -171,11 +180,8 @@
         index++;
     }
 
-    if (cppFilename.size() == 0
-            && headerFilename.size() == 0
-            && javaFilename.size() == 0
-            && atomsInfoHeaderFilename.size() == 0
-            && atomsInfoCppFilename.size() == 0) {
+    if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0 &&
+        atomsInfoHeaderFilename.size() == 0 && atomsInfoCppFilename.size() == 0) {
         print_usage();
         return 1;
     }
@@ -201,8 +207,8 @@
 
     AtomDecl attributionDecl;
     vector<java_type_t> attributionSignature;
-    collate_atom(android::os::statsd::AttributionNode::descriptor(),
-                 &attributionDecl, &attributionSignature);
+    collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
+                 &attributionSignature);
 
     // Write the atoms info .cpp file
     if (atomsInfoCppFilename.size() != 0) {
@@ -211,8 +217,8 @@
             fprintf(stderr, "Unable to open file for write: %s\n", atomsInfoCppFilename.c_str());
             return 1;
         }
-        errorCount = android::stats_log_api_gen::write_atoms_info_cpp(
-            out, atoms, cppNamespace, atomsInfoCppHeaderImport);
+        errorCount = android::stats_log_api_gen::write_atoms_info_cpp(out, atoms, cppNamespace,
+                                                                      atomsInfoCppHeaderImport);
         fclose(out);
     }
 
@@ -227,7 +233,6 @@
         fclose(out);
     }
 
-
     // Write the .cpp file
     if (cppFilename.size() != 0) {
         FILE* out = fopen(cppFilename.c_str(), "w");
@@ -240,13 +245,14 @@
             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
             return 1;
         }
-        // If this is for a specific module, the header file to import must also be provided.
+        // If this is for a specific module, the header file to import must also be
+        // provided.
         if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
             fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
             return 1;
         }
         errorCount = android::stats_log_api_gen::write_stats_log_cpp(
-            out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
+                out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
         fclose(out);
     }
 
@@ -261,8 +267,8 @@
         if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
             fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
         }
-        errorCount = android::stats_log_api_gen::write_stats_log_header(
-            out, atoms, attributionDecl, cppNamespace);
+        errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
+                                                                        cppNamespace);
         fclose(out);
     }
 
@@ -291,8 +297,7 @@
 
         if (compileQ) {
             errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
-                    out, atoms, attributionDecl, javaClass, javaPackage,
-                    supportWorkSource);
+                    out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource);
         } else {
             errorCount = android::stats_log_api_gen::write_stats_log_java(
                     out, atoms, attributionDecl, javaClass, javaPackage, supportQ,
@@ -311,9 +316,7 @@
 /**
  * Main.
  */
-int
-main(int argc, char const*const* argv)
-{
+int main(int argc, char const* const* argv) {
     GOOGLE_PROTOBUF_VERIFY_VERSION;
 
     return android::stats_log_api_gen::run(argc, argv);
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 90dcae4..0cf3225 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -15,45 +15,38 @@
  */
 
 #include "native_writer.h"
+
 #include "utils.h"
 
 namespace android {
 namespace stats_log_api_gen {
 
-static void write_annotations(
-        FILE* out, int argIndex,
-        const FieldNumberToAnnotations& fieldNumberToAnnotations,
-        const string& methodPrefix,
-        const string& methodSuffix) {
+static void write_annotations(FILE* out, int argIndex,
+                              const FieldNumberToAnnotations& fieldNumberToAnnotations,
+                              const string& methodPrefix, const string& methodSuffix) {
     auto fieldNumberToAnnotationsIt = fieldNumberToAnnotations.find(argIndex);
     if (fieldNumberToAnnotationsIt == fieldNumberToAnnotations.end()) {
         return;
     }
-    const set<shared_ptr<Annotation>>& annotations =
-            fieldNumberToAnnotationsIt->second;
+    const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotationsIt->second;
     for (const shared_ptr<Annotation>& annotation : annotations) {
         // TODO(b/151744250): Group annotations for same atoms.
         // TODO(b/151786433): Write atom constant name instead of atom id literal.
         fprintf(out, "    if (code == %d) {\n", annotation->atomId);
-        switch(annotation->type) {
-            // TODO(b/151776731): Check for reset state annotation and only include reset state
-            // when field value == default state annotation value.
+        switch (annotation->type) {
+            // TODO(b/151776731): Check for reset state annotation and only include
+            // reset state when field value == default state annotation value.
             case ANNOTATION_TYPE_INT:
                 // TODO(b/151786433): Write annotation constant name instead of
                 // annotation id literal.
-                fprintf(out, "        %saddInt32Annotation(%s%d, %d);\n",
-                        methodPrefix.c_str(),
-                        methodSuffix.c_str(),
-                        annotation->annotationId,
-                        annotation->value.intValue);
+                fprintf(out, "        %saddInt32Annotation(%s%d, %d);\n", methodPrefix.c_str(),
+                        methodSuffix.c_str(), annotation->annotationId, annotation->value.intValue);
                 break;
             case ANNOTATION_TYPE_BOOL:
                 // TODO(b/151786433): Write annotation constant name instead of
                 // annotation id literal.
-                fprintf(out, "        %saddBoolAnnotation(%s%d, %s);\n",
-                        methodPrefix.c_str(),
-                        methodSuffix.c_str(),
-                        annotation->annotationId,
+                fprintf(out, "        %saddBoolAnnotation(%s%d, %s);\n", methodPrefix.c_str(),
+                        methodSuffix.c_str(), annotation->annotationId,
                         annotation->value.boolValue ? "true" : "false");
                 break;
             default:
@@ -61,29 +54,28 @@
         }
         fprintf(out, "    }\n");
     }
-
 }
 
 static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl, const bool supportQ) {
+                                            const AtomDecl& attributionDecl, const bool supportQ) {
     fprintf(out, "\n");
     for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
-            signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
         vector<java_type_t> signature = signatureInfoMapIt->first;
         const FieldNumberToAnnotations& fieldNumberToAnnotations = signatureInfoMapIt->second;
         // Key value pairs not supported in native.
         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
             continue;
         }
-        write_native_method_signature(out, "int stats_write", signature,
-                attributionDecl, " {");
+        write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
 
         int argIndex = 1;
         if (supportQ) {
             fprintf(out, "    StatsEventCompat event;\n");
             fprintf(out, "    event.setAtomId(code);\n");
+            write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "event.", "");
             for (vector<java_type_t>::const_iterator arg = signature.begin();
-                    arg != signature.end(); arg++) {
+                 arg != signature.end(); arg++) {
                 switch (*arg) {
                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
                         const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -99,7 +91,7 @@
                     case JAVA_TYPE_BOOLEAN:
                         fprintf(out, "    event.writeBool(arg%d);\n", argIndex);
                         break;
-                    case JAVA_TYPE_INT: // Fall through.
+                    case JAVA_TYPE_INT:  // Fall through.
                     case JAVA_TYPE_ENUM:
                         fprintf(out, "    event.writeInt32(arg%d);\n", argIndex);
                         break;
@@ -124,8 +116,10 @@
         } else {
             fprintf(out, "    AStatsEvent* event = AStatsEvent_obtain();\n");
             fprintf(out, "    AStatsEvent_setAtomId(event, code);\n");
+            write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAnnotations, "AStatsEvent_",
+                              "event, ");
             for (vector<java_type_t>::const_iterator arg = signature.begin();
-                    arg != signature.end(); arg++) {
+                 arg != signature.end(); arg++) {
                 switch (*arg) {
                     case JAVA_TYPE_ATTRIBUTION_CHAIN: {
                         const char* uidName = attributionDecl.fields.front().name.c_str();
@@ -140,13 +134,14 @@
                     case JAVA_TYPE_BYTE_ARRAY:
                         fprintf(out,
                                 "    AStatsEvent_writeByteArray(event, "
-                                "reinterpret_cast<const uint8_t*>(arg%d.arg), arg%d.arg_length);\n",
+                                "reinterpret_cast<const uint8_t*>(arg%d.arg), "
+                                "arg%d.arg_length);\n",
                                 argIndex, argIndex);
                         break;
                     case JAVA_TYPE_BOOLEAN:
                         fprintf(out, "    AStatsEvent_writeBool(event, arg%d);\n", argIndex);
                         break;
-                    case JAVA_TYPE_INT: // Fall through.
+                    case JAVA_TYPE_INT:  // Fall through.
                     case JAVA_TYPE_ENUM:
                         fprintf(out, "    AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
                         break;
@@ -165,7 +160,7 @@
                         return 1;
                 }
                 write_annotations(out, argIndex, fieldNumberToAnnotations, "AStatsEvent_",
-                        "event, ");
+                                  "event, ");
                 argIndex++;
             }
             fprintf(out, "    const int ret = AStatsEvent_write(event);\n");
@@ -178,10 +173,10 @@
 }
 
 static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
-        const AtomDecl& attributionDecl) {
+                                                         const AtomDecl& attributionDecl) {
     fprintf(out, "\n");
     for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
-            signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
+         signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
         vector<java_type_t> signature = signature_it->first;
         // Key value pairs not supported in native.
         if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
@@ -189,7 +184,7 @@
         }
 
         write_native_method_signature(out, "int stats_write_non_chained", signature,
-                attributionDecl, " {");
+                                      attributionDecl, " {");
 
         vector<java_type_t> newSignature;
 
@@ -212,17 +207,14 @@
 
         fprintf(out, "}\n\n");
     }
-
 }
 
 static void write_native_method_header(
-        FILE* out,
-        const string& methodName,
+        FILE* out, const string& methodName,
         const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap,
-        const AtomDecl &attributionDecl) {
-
+        const AtomDecl& attributionDecl) {
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
-            signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         vector<java_type_t> signature = signatureInfoMapIt->first;
 
         // Key value pairs not supported in native.
@@ -233,9 +225,9 @@
     }
 }
 
-int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
-                        const string& cppNamespace,
-                        const string& importHeader, const bool supportQ) {
+int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                        const string& cppNamespace, const string& importHeader,
+                        const bool supportQ) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -260,8 +252,8 @@
     return 0;
 }
 
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-        const string& cppNamespace) {
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                           const string& cppNamespace) {
     // Print prelude
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
@@ -286,21 +278,18 @@
     fprintf(out, "//\n");
     fprintf(out, "// Constants for enum values\n");
     fprintf(out, "//\n\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-        atom != atoms.decls.end(); atom++) {
-
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
-            field != atom->fields.end(); field++) {
+             field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ENUM) {
-                fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
-                    field->name.c_str());
+                fprintf(out, "// Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
                 for (map<int, string>::const_iterator value = field->enumValues.begin();
-                    value != field->enumValues.end(); value++) {
+                     value != field->enumValues.end(); value++) {
                     fprintf(out, "const int32_t %s__%s__%s = %d;\n",
-                        make_constant_name(atom->message).c_str(),
-                        make_constant_name(field->name).c_str(),
-                        make_constant_name(value->second).c_str(),
-                        value->first);
+                            make_constant_name(atom->message).c_str(),
+                            make_constant_name(field->name).c_str(),
+                            make_constant_name(value->second).c_str(), value->first);
                 }
                 fprintf(out, "\n");
             }
@@ -325,8 +314,8 @@
     fprintf(out, "//\n");
     fprintf(out, "// Write flattened methods\n");
     fprintf(out, "//\n");
-    write_native_method_header(out, "int stats_write_non_chained",
-            atoms.nonChainedSignatureInfoMap, attributionDecl);
+    write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
+                               attributionDecl);
 
     fprintf(out, "\n");
     write_closing_namespace(out, cppNamespace);
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
index 6e60325..264d4db 100644
--- a/tools/stats_log_api_gen/native_writer.h
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -16,22 +16,22 @@
 
 #pragma once
 
-#include "Collation.h"
-
 #include <stdio.h>
 #include <string.h>
 
+#include "Collation.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
 using namespace std;
 
-int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
-        const string& cppNamespace, const string& importHeader,
-        const bool supportQ);
+int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                        const string& cppNamespace, const string& importHeader,
+                        const bool supportQ);
 
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
-        const string& cppNamespace);
+int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
+                           const string& cppNamespace);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 5032ac0..9878926 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -15,12 +15,11 @@
  */
 
 #include <gtest/gtest.h>
-
-#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
-#include "Collation.h"
-
 #include <stdio.h>
 
+#include "Collation.h"
+#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
+
 namespace android {
 namespace stats_log_api_gen {
 
@@ -31,14 +30,13 @@
 /**
  * Return whether the map contains a vector of the elements provided.
  */
-static bool
-map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s, int count, ...)
-{
+static bool map_contains_vector(const map<vector<java_type_t>, FieldNumberToAnnotations>& s,
+                                int count, ...) {
     va_list args;
     vector<java_type_t> v;
 
     va_start(args, count);
-    for (int i=0; i<count; i++) {
+    for (int i = 0; i < count; i++) {
         v.push_back((java_type_t)va_arg(args, int));
     }
     va_end(args);
@@ -49,34 +47,33 @@
 /**
  * Expect that the provided map contains the elements provided.
  */
-#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
-    do { \
-        int count = sizeof((int[]){__VA_ARGS__})/sizeof(int); \
+#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...)                    \
+    do {                                                         \
+        int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int);  \
         EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \
-    } while(0)
+    } while (0)
 
 /** Expects that the provided atom has no enum values for any field. */
-#define EXPECT_NO_ENUM_FIELD(atom) \
-    do { \
+#define EXPECT_NO_ENUM_FIELD(atom)                                           \
+    do {                                                                     \
         for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
-             field != atom->fields.end(); field++) { \
-            EXPECT_TRUE(field->enumValues.empty()); \
-        } \
-    } while(0)
+             field != atom->fields.end(); field++) {                         \
+            EXPECT_TRUE(field->enumValues.empty());                          \
+        }                                                                    \
+    } while (0)
 
 /** Expects that exactly one specific field has expected enum values. */
-#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values)        \
-    do { \
+#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values)                      \
+    do {                                                                     \
         for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
-             field != atom->fields.end(); field++) { \
-            if (field->name == field_name) { \
-                EXPECT_EQ(field->enumValues, values); \
-            } else { \
-                EXPECT_TRUE(field->enumValues.empty()); \
-            } \
-        } \
-    } while(0)
-
+             field != atom->fields.end(); field++) {                         \
+            if (field->name == field_name) {                                 \
+                EXPECT_EQ(field->enumValues, values);                        \
+            } else {                                                         \
+                EXPECT_TRUE(field->enumValues.empty());                      \
+            }                                                                \
+        }                                                                    \
+    } while (0)
 
 /**
  * Test a correct collation, with all the types.
@@ -95,23 +92,22 @@
     EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
 
     // AllTypesAtom
-    EXPECT_MAP_CONTAINS_SIGNATURE(
-        atoms.signatureInfoMap,
-        JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
-        JAVA_TYPE_FLOAT,             // float
-        JAVA_TYPE_LONG,              // int64
-        JAVA_TYPE_LONG,              // uint64
-        JAVA_TYPE_INT,               // int32
-        JAVA_TYPE_LONG,              // fixed64
-        JAVA_TYPE_INT,               // fixed32
-        JAVA_TYPE_BOOLEAN,           // bool
-        JAVA_TYPE_STRING,            // string
-        JAVA_TYPE_INT,               // uint32
-        JAVA_TYPE_INT,               // AnEnum
-        JAVA_TYPE_INT,               // sfixed32
-        JAVA_TYPE_LONG,              // sfixed64
-        JAVA_TYPE_INT,               // sint32
-        JAVA_TYPE_LONG               // sint64
+    EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap,
+                                  JAVA_TYPE_ATTRIBUTION_CHAIN,  // AttributionChain
+                                  JAVA_TYPE_FLOAT,              // float
+                                  JAVA_TYPE_LONG,               // int64
+                                  JAVA_TYPE_LONG,               // uint64
+                                  JAVA_TYPE_INT,                // int32
+                                  JAVA_TYPE_LONG,               // fixed64
+                                  JAVA_TYPE_INT,                // fixed32
+                                  JAVA_TYPE_BOOLEAN,            // bool
+                                  JAVA_TYPE_STRING,             // string
+                                  JAVA_TYPE_INT,                // uint32
+                                  JAVA_TYPE_INT,                // AnEnum
+                                  JAVA_TYPE_INT,                // sfixed32
+                                  JAVA_TYPE_LONG,               // sfixed64
+                                  JAVA_TYPE_INT,                // sint32
+                                  JAVA_TYPE_LONG                // sint64
     );
 
     set<AtomDecl>::const_iterator atom = atoms.decls.begin();
@@ -156,7 +152,8 @@
 }
 
 /**
- * Test that atoms that have non-primitive types or repeated fields are rejected.
+ * Test that atoms that have non-primitive types or repeated fields are
+ * rejected.
  */
 TEST(CollationTest, FailOnBadTypes) {
     Atoms atoms;
@@ -170,18 +167,20 @@
  */
 TEST(CollationTest, FailOnSkippedFieldsSingle) {
     Atoms atoms;
-    int errorCount = collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+    int errorCount =
+            collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
 
     EXPECT_EQ(1, errorCount);
 }
 
 /**
- * Test that atoms that skip field numbers (not in the first position, and multiple
- * times) are rejected.
+ * Test that atoms that skip field numbers (not in the first position, and
+ * multiple times) are rejected.
  */
 TEST(CollationTest, FailOnSkippedFieldsMultiple) {
     Atoms atoms;
-    int errorCount = collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+    int errorCount =
+            collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
 
     EXPECT_EQ(2, errorCount);
 }
@@ -191,11 +190,11 @@
  * rejected.
  */
 TEST(CollationTest, FailBadAttributionNodePosition) {
-  Atoms atoms;
-  int errorCount =
-      collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
 
-  EXPECT_EQ(1, errorCount);
+    EXPECT_EQ(1, errorCount);
 }
 
 TEST(CollationTest, FailOnBadStateAtomOptions) {
@@ -270,8 +269,8 @@
             const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(1);
             EXPECT_EQ(2u, annotations.size());
             for (const shared_ptr<Annotation> annotation : annotations) {
-                EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID
-                        || annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
+                EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
+                            annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
                 if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
                     EXPECT_EQ(1, annotation->atomId);
                     EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
@@ -303,12 +302,11 @@
         EXPECT_EQ(1u, fieldNumberToAnnotations.size());
         int fieldNumber = 1;
         EXPECT_NE(fieldNumberToAnnotations.end(), fieldNumberToAnnotations.find(fieldNumber));
-        const set<shared_ptr<Annotation>>& annotations =
-                fieldNumberToAnnotations.at(fieldNumber);
+        const set<shared_ptr<Annotation>>& annotations = fieldNumberToAnnotations.at(fieldNumber);
         EXPECT_EQ(2u, annotations.size());
         for (const shared_ptr<Annotation> annotation : annotations) {
-            EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID
-                    || annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
+            EXPECT_TRUE(annotation->annotationId == ANNOTATION_ID_IS_UID ||
+                        annotation->annotationId == ANNOTATION_ID_STATE_OPTION);
             if (ANNOTATION_ID_IS_UID == annotation->annotationId) {
                 EXPECT_EQ(1, annotation->atomId);
                 EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index 7314127..0262488 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -22,9 +22,9 @@
 namespace stats_log_api_gen {
 
 static void build_non_chained_decl_map(const Atoms& atoms,
-                                std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
+                                       std::map<int, set<AtomDecl>::const_iterator>* decl_map) {
     for (set<AtomDecl>::const_iterator atom = atoms.non_chained_decls.begin();
-        atom != atoms.non_chained_decls.end(); atom++) {
+         atom != atoms.non_chained_decls.end(); atom++) {
         decl_map->insert(std::make_pair(atom->code, atom));
     }
 }
@@ -36,7 +36,7 @@
     string result;
     const int N = str.size();
     bool underscore_next = false;
-    for (int i=0; i<N; i++) {
+    for (int i = 0; i < N; i++) {
         char c = str[i];
         if (c >= 'A' && c <= 'Z') {
             if (underscore_next) {
@@ -99,7 +99,8 @@
 }
 
 // Native
-// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+// Writes namespaces for the cpp and header files, returning the number of
+// namespaces written.
 void write_namespace(FILE* out, const string& cppNamespaces) {
     vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
     for (string cppNamespace : cppNamespaceVec) {
@@ -115,35 +116,31 @@
     }
 }
 
-static void write_cpp_usage(
-    FILE* out, const string& method_name, const string& atom_code_name,
-    const AtomDecl& atom, const AtomDecl &attributionDecl) {
-    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(),
-            atom_code_name.c_str());
+static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
+                            const AtomDecl& atom, const AtomDecl& attributionDecl) {
+    fprintf(out, "     * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
 
-    for (vector<AtomField>::const_iterator field = atom.fields.begin();
-            field != atom.fields.end(); field++) {
+    for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
+         field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
             for (auto chainField : attributionDecl.fields) {
                 if (chainField.javaType == JAVA_TYPE_STRING) {
-                    fprintf(out, ", const std::vector<%s>& %s",
-                         cpp_type_name(chainField.javaType),
-                         chainField.name.c_str());
+                    fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
+                            chainField.name.c_str());
                 } else {
                     fprintf(out, ", const %s* %s, size_t %s_length",
-                         cpp_type_name(chainField.javaType),
-                         chainField.name.c_str(), chainField.name.c_str());
+                            cpp_type_name(chainField.javaType), chainField.name.c_str(),
+                            chainField.name.c_str());
                 }
             }
         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
-            fprintf(out, ", const std::map<int, int32_t>& %s_int"
-                         ", const std::map<int, int64_t>& %s_long"
-                         ", const std::map<int, char const*>& %s_str"
-                         ", const std::map<int, float>& %s_float",
-                         field->name.c_str(),
-                         field->name.c_str(),
-                         field->name.c_str(),
-                         field->name.c_str());
+            fprintf(out,
+                    ", const std::map<int, int32_t>& %s_int"
+                    ", const std::map<int, int64_t>& %s_long"
+                    ", const std::map<int, char const*>& %s_str"
+                    ", const std::map<int, float>& %s_float",
+                    field->name.c_str(), field->name.c_str(), field->name.c_str(),
+                    field->name.c_str());
         } else {
             fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
         }
@@ -162,8 +159,8 @@
 
     size_t i = 0;
     // Print atom constants
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-        atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         string constant = make_constant_name(atom->name);
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
@@ -173,7 +170,7 @@
         auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
         if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
             write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
-                attributionDecl);
+                            attributionDecl);
         }
         fprintf(out, "     */\n");
         char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
@@ -186,30 +183,30 @@
 }
 
 void write_native_method_signature(FILE* out, const string& methodName,
-        const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
-        const string& closer) {
+                                   const vector<java_type_t>& signature,
+                                   const AtomDecl& attributionDecl, const string& closer) {
     fprintf(out, "%s(int32_t code", methodName.c_str());
     int argIndex = 1;
-    for (vector<java_type_t>::const_iterator arg = signature.begin();
-        arg != signature.end(); arg++) {
+    for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+         arg++) {
         if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
             for (auto chainField : attributionDecl.fields) {
                 if (chainField.javaType == JAVA_TYPE_STRING) {
-                        fprintf(out, ", const std::vector<%s>& %s",
-                             cpp_type_name(chainField.javaType),
-                             chainField.name.c_str());
+                    fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
+                            chainField.name.c_str());
                 } else {
-                        fprintf(out, ", const %s* %s, size_t %s_length",
-                             cpp_type_name(chainField.javaType),
-                             chainField.name.c_str(), chainField.name.c_str());
+                    fprintf(out, ", const %s* %s, size_t %s_length",
+                            cpp_type_name(chainField.javaType), chainField.name.c_str(),
+                            chainField.name.c_str());
                 }
             }
         } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-            fprintf(out, ", const std::map<int, int32_t>& arg%d_1, "
-                         "const std::map<int, int64_t>& arg%d_2, "
-                         "const std::map<int, char const*>& arg%d_3, "
-                         "const std::map<int, float>& arg%d_4",
-                         argIndex, argIndex, argIndex, argIndex);
+            fprintf(out,
+                    ", const std::map<int, int32_t>& arg%d_1, "
+                    "const std::map<int, int64_t>& arg%d_2, "
+                    "const std::map<int, char const*>& arg%d_3, "
+                    "const std::map<int, float>& arg%d_4",
+                    argIndex, argIndex, argIndex, argIndex);
         } else {
             fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
         }
@@ -219,27 +216,27 @@
 }
 
 void write_native_method_call(FILE* out, const string& methodName,
-        const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex) {
+                              const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+                              int argIndex) {
     fprintf(out, "%s(code", methodName.c_str());
-    for (vector<java_type_t>::const_iterator arg = signature.begin();
-       arg != signature.end(); arg++) {
-       if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
-           for (auto chainField : attributionDecl.fields) {
-               if (chainField.javaType == JAVA_TYPE_STRING) {
-                       fprintf(out, ", %s",
+    for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+         arg++) {
+        if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+            for (auto chainField : attributionDecl.fields) {
+                if (chainField.javaType == JAVA_TYPE_STRING) {
+                    fprintf(out, ", %s", chainField.name.c_str());
+                } else {
+                    fprintf(out, ",  %s,  %s_length", chainField.name.c_str(),
                             chainField.name.c_str());
-               } else {
-                       fprintf(out, ",  %s,  %s_length",
-                            chainField.name.c_str(), chainField.name.c_str());
-               }
-           }
-       } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
-           fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex,
-                   argIndex, argIndex, argIndex);
-       } else {
-           fprintf(out, ", arg%d", argIndex);
-       }
-       argIndex++;
+                }
+            }
+        } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+            fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex,
+                    argIndex);
+        } else {
+            fprintf(out, ", arg%d", argIndex);
+        }
+        argIndex++;
     }
     fprintf(out, ");\n");
 }
@@ -252,8 +249,8 @@
     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
 
     // Print constants for the atom codes.
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-            atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         string constant = make_constant_name(atom->name);
         fprintf(out, "\n");
         fprintf(out, "    /**\n");
@@ -271,20 +268,19 @@
 
 void write_java_enum_values(FILE* out, const Atoms& atoms) {
     fprintf(out, "    // Constants for enum values.\n\n");
-    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
-        atom != atoms.decls.end(); atom++) {
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end();
+         atom++) {
         for (vector<AtomField>::const_iterator field = atom->fields.begin();
-            field != atom->fields.end(); field++) {
+             field != atom->fields.end(); field++) {
             if (field->javaType == JAVA_TYPE_ENUM) {
                 fprintf(out, "    // Values for %s.%s\n", atom->message.c_str(),
-                    field->name.c_str());
+                        field->name.c_str());
                 for (map<int, string>::const_iterator value = field->enumValues.begin();
-                    value != field->enumValues.end(); value++) {
+                     value != field->enumValues.end(); value++) {
                     fprintf(out, "    public static final int %s__%s__%s = %d;\n",
-                        make_constant_name(atom->message).c_str(),
-                        make_constant_name(field->name).c_str(),
-                        make_constant_name(value->second).c_str(),
-                        value->first);
+                            make_constant_name(atom->message).c_str(),
+                            make_constant_name(field->name).c_str(),
+                            make_constant_name(value->second).c_str(), value->first);
                 }
                 fprintf(out, "\n");
             }
@@ -293,11 +289,11 @@
 }
 
 void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
-        const AtomDecl& atom) {
-    fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s",
-        method_name.c_str(), atom_code_name.c_str());
-    for (vector<AtomField>::const_iterator field = atom.fields.begin();
-        field != atom.fields.end(); field++) {
+                      const AtomDecl& atom) {
+    fprintf(out, "     * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
+            atom_code_name.c_str());
+    for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
+         field++) {
         if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
             fprintf(out, ", android.os.WorkSource workSource");
         } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
@@ -312,16 +308,15 @@
 }
 
 int write_java_non_chained_methods(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
-            signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         // Print method signature.
         fprintf(out, "    public static void write_non_chained(int code");
         vector<java_type_t> signature = signatureInfoMapIt->first;
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
                 return 1;
@@ -337,8 +332,8 @@
 
         fprintf(out, "        write(code");
         argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             // First two args are uid and tag of attribution chain.
             if (argIndex == 1) {
                 fprintf(out, ", new int[] {arg%d}", argIndex);
@@ -357,23 +352,24 @@
 }
 
 int write_java_work_source_methods(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap) {
     fprintf(out, "    // WorkSource methods.\n");
     for (auto signatureInfoMapIt = signatureInfoMap.begin();
-            signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+         signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
         vector<java_type_t> signature = signatureInfoMapIt->first;
         // Determine if there is Attribution in this signature.
         int attributionArg = -1;
         int argIndexMax = 0;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             argIndexMax++;
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 if (attributionArg > -1) {
                     fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
                     fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
-                    fprintf(out, "\n// Invalid for WorkSource: more than one attribution chain.\n");
+                    fprintf(out,
+                            "\n// Invalid for WorkSource: more than one attribution "
+                            "chain.\n");
                     return 1;
                 }
                 attributionArg = argIndexMax;
@@ -387,8 +383,8 @@
         // Method header (signature)
         fprintf(out, "    public static void write(int code");
         int argIndex = 1;
-        for (vector<java_type_t>::const_iterator arg = signature.begin();
-                arg != signature.end(); arg++) {
+        for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
+             arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
                 fprintf(out, ", android.os.WorkSource ws");
             } else {
@@ -398,36 +394,40 @@
         }
         fprintf(out, ") {\n");
 
-        // write_non_chained() component. TODO: Remove when flat uids are no longer needed.
+        // write_non_chained() component. TODO: Remove when flat uids are no longer
+        // needed.
         fprintf(out, "        for (int i = 0; i < ws.size(); ++i) {\n");
         fprintf(out, "            write_non_chained(code");
         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
             if (argIndex == attributionArg) {
                 fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
             } else {
-               fprintf(out, ", arg%d", argIndex);
+                fprintf(out, ", arg%d", argIndex);
             }
         }
         fprintf(out, ");\n");
-        fprintf(out, "        }\n"); // close for-loop
+        fprintf(out, "        }\n");  // close for-loop
 
         // write() component.
-        fprintf(out, "        java.util.List<android.os.WorkSource.WorkChain> workChains = "
+        fprintf(out,
+                "        java.util.List<android.os.WorkSource.WorkChain> workChains = "
                 "ws.getWorkChains();\n");
         fprintf(out, "        if (workChains != null) {\n");
-        fprintf(out, "            for (android.os.WorkSource.WorkChain wc : workChains) {\n");
+        fprintf(out,
+                "            for (android.os.WorkSource.WorkChain wc : workChains) "
+                "{\n");
         fprintf(out, "                write(code");
         for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
             if (argIndex == attributionArg) {
                 fprintf(out, ", wc.getUids(), wc.getTags()");
             } else {
-               fprintf(out, ", arg%d", argIndex);
+                fprintf(out, ", arg%d", argIndex);
             }
         }
         fprintf(out, ");\n");
-        fprintf(out, "            }\n"); // close for-loop
-        fprintf(out, "        }\n"); // close if
-        fprintf(out, "    }\n"); // close method
+        fprintf(out, "            }\n");  // close for-loop
+        fprintf(out, "        }\n");      // close if
+        fprintf(out, "    }\n");          // close method
     }
     return 0;
 }
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index a6b3ef9..468f323 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -16,14 +16,14 @@
 
 #pragma once
 
-#include "Collation.h"
+#include <stdio.h>
+#include <string.h>
 
 #include <map>
 #include <set>
 #include <vector>
 
-#include <stdio.h>
-#include <string.h>
+#include "Collation.h"
 
 namespace android {
 namespace stats_log_api_gen {
@@ -52,11 +52,12 @@
 void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
 
 void write_native_method_signature(FILE* out, const string& methodName,
-        const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
-        const string& closer);
+                                   const vector<java_type_t>& signature,
+                                   const AtomDecl& attributionDecl, const string& closer);
 
 void write_native_method_call(FILE* out, const string& methodName,
-        const vector<java_type_t>& signature, const AtomDecl& attributionDecl, int argIndex = 1);
+                              const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
+                              int argIndex = 1);
 
 // Common Java helpers.
 void write_java_atom_codes(FILE* out, const Atoms& atoms);
@@ -64,14 +65,13 @@
 void write_java_enum_values(FILE* out, const Atoms& atoms);
 
 void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
-        const AtomDecl& atom);
+                      const AtomDecl& atom);
 
-int write_java_non_chained_methods(FILE* out, const map<vector<java_type_t>,
-        FieldNumberToAnnotations>& signatureInfoMap);
+int write_java_non_chained_methods(
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
 
 int write_java_work_source_methods(
-        FILE* out,
-        const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
+        FILE* out, const map<vector<java_type_t>, FieldNumberToAnnotations>& signatureInfoMap);
 
 }  // namespace stats_log_api_gen
 }  // namespace android
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 9d9a495..d0f1a26 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -170,24 +170,23 @@
 java_library {
     name: "framework-wifi-stubs-publicapi",
     srcs: [":framework-wifi-stubs-srcs-publicapi"],
+    defaults: ["framework-module-stubs-lib-defaults-publicapi"],
+    // TODO(b/151134996): remove this
     sdk_version: "current",
-    installable: false,
 }
 
 java_library {
     name: "framework-wifi-stubs-systemapi",
     srcs: [":framework-wifi-stubs-srcs-systemapi"],
-    sdk_version: "system_current",
     libs: ["framework-annotations-lib"],
-    installable: false,
+    defaults: ["framework-module-stubs-lib-defaults-systemapi"],
 }
 
 java_library {
     name: "framework-wifi-stubs-module_libs_api",
     srcs: [":framework-wifi-stubs-srcs-module_libs_api"],
-    sdk_version: "module_current",
     libs: ["framework-annotations-lib"],
-    installable: false,
+    defaults: ["framework-module-stubs-lib-defaults-module_libs_api"],
 }
 
 // defaults for tests that need to build against framework-wifi's @hide APIs
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index a269e17..457e0db 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -516,9 +516,6 @@
     public WifiConfiguration toWifiConfiguration() {
         WifiConfiguration wifiConfig = new WifiConfiguration();
         wifiConfig.SSID = mSsid;
-        if (mBssid != null) {
-            wifiConfig.BSSID = mBssid.toString();
-        }
         wifiConfig.preSharedKey = mPassphrase;
         wifiConfig.hiddenSSID = mHiddenSsid;
         wifiConfig.apChannel = mChannel;
@@ -662,8 +659,6 @@
         /**
          * Specifies a BSSID for the AP.
          * <p>
-         * Only supported when configuring a local-only hotspot.
-         * <p>
          * <li>If not set, defaults to null.</li>
          * @param bssid BSSID, or null to have the BSSID chosen by the framework. The caller is
          *              responsible for avoiding collisions.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ba68d17..b110a61 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2356,6 +2356,8 @@
         sbuf.append(" lcuid=" + lastConnectUid);
         sbuf.append(" allowAutojoin=" + allowAutojoin);
         sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected);
+        sbuf.append(" mostRecentlyConnected=" + isMostRecentlyConnected);
+
         sbuf.append(" ");
 
         if (this.lastConnected != 0) {
@@ -2964,4 +2966,11 @@
         return mPasspointUniqueId;
     }
 
+    /**
+     * If network is one of the most recently connected.
+     * For framework internal use only. Do not parcel.
+     * @hide
+     */
+    public boolean isMostRecentlyConnected = false;
+
 }