Merge "Reset IME insets source frame at begin layout" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 78d38c5..71513b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -470,7 +470,7 @@
         "framework-statsd-stubs-module_libs_api",
         "framework-permission-stubs-systemapi",
         "framework-wifi-stubs-systemapi",
-        "framework-tethering-stubs",
+        "framework-tethering-stubs-module_libs_api",
     ],
     installable: true,
     javac_shard_size: 150,
@@ -518,7 +518,7 @@
         "framework-sdkextensions-stubs-systemapi",
         "framework-statsd-stubs-module_libs_api",
         "framework-wifi-stubs-systemapi",
-        "framework-tethering-stubs",
+        "framework-tethering-stubs-module_libs_api",
         // TODO (b/147688669) should be framework-telephony-stubs
         "framework-telephony",
         // TODO(jiyong): add stubs for APEXes here
@@ -540,7 +540,6 @@
     visibility: [
         // DO NOT ADD ANY MORE ENTRIES TO THIS LIST
         "//external/robolectric-shadows:__subpackages__",
-        "//frameworks/base/packages/Tethering/common/TetheringLib:__subpackages__",
         "//frameworks/layoutlib:__subpackages__",
         "//frameworks/opt/net/ike:__subpackages__",
     ],
diff --git a/apex/Android.bp b/apex/Android.bp
index 051986e..1510911 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -43,6 +43,7 @@
     name: "framework-module-stubs-defaults-publicapi",
     args: mainline_stubs_args,
     installable: false,
+    sdk_version: "current",
 }
 
 stubs_defaults {
@@ -50,6 +51,7 @@
     args: mainline_stubs_args + priv_apps,
     srcs: [":framework-annotations"],
     installable: false,
+    sdk_version: "system_current",
 }
 
 // The defaults for module_libs comes in two parts - defaults for API checks
@@ -62,6 +64,7 @@
     args: mainline_stubs_args + module_libs,
     srcs: [":framework-annotations"],
     installable: false,
+    sdk_version: "module_current",
 }
 
 stubs_defaults {
@@ -69,4 +72,5 @@
     args: mainline_stubs_args + module_libs + priv_apps,
     srcs: [":framework-annotations"],
     installable: false,
+    sdk_version: "module_current",
 }
diff --git a/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java b/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
new file mode 100644
index 0000000..3725ad4
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/AccessorInfo.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.blob;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Class to provide information about an accessor of a shared blob.
+ *
+ * @hide
+ */
+public final class AccessorInfo implements Parcelable {
+    private final String mPackageName;
+    private final long mExpiryTimeMs;
+    private final int mDescriptionResId;
+    private final CharSequence mDescription;
+
+    public AccessorInfo(String packageName, long expiryTimeMs,
+            int descriptionResId, CharSequence description) {
+        mPackageName = packageName;
+        mExpiryTimeMs = expiryTimeMs;
+        mDescriptionResId = descriptionResId;
+        mDescription = description;
+    }
+
+    private AccessorInfo(Parcel in) {
+        mPackageName = in.readString();
+        mExpiryTimeMs = in.readLong();
+        mDescriptionResId = in.readInt();
+        mDescription = in.readCharSequence();
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    public long getExpiryTimeMs() {
+        return mExpiryTimeMs;
+    }
+
+    public int getDescriptionResId() {
+        return mDescriptionResId;
+    }
+
+    public CharSequence getDescription() {
+        return mDescription;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(mPackageName);
+        dest.writeLong(mExpiryTimeMs);
+        dest.writeInt(mDescriptionResId);
+        dest.writeCharSequence(mDescription);
+    }
+
+    @Override
+    public String toString() {
+        return "AccessorInfo {"
+                + "package: " + mPackageName + ","
+                + "expiryMs: " + mExpiryTimeMs + ","
+                + "descriptionResId: " + mDescriptionResId + ","
+                + "description: " + mDescription + ","
+                + "}";
+    }
+
+    private String toShortString() {
+        return mPackageName;
+    }
+
+    public static String toShortString(List<AccessorInfo> accessors) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for (int i = 0, size = accessors.size(); i < size; ++i) {
+            sb.append(accessors.get(i).toShortString());
+            sb.append(",");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<AccessorInfo> CREATOR = new Creator<AccessorInfo>() {
+        @Override
+        @NonNull
+        public AccessorInfo createFromParcel(Parcel source) {
+            return new AccessorInfo(source);
+        }
+
+        @Override
+        @NonNull
+        public AccessorInfo[] newArray(int size) {
+            return new AccessorInfo[size];
+        }
+    };
+}
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl
similarity index 65%
copy from wifi/java/android/net/wifi/IScoreChangeCallback.aidl
copy to apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl
index d691f41..2549773 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 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.
@@ -13,17 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package android.app.blob;
 
-package android.net.wifi;
-
-/**
- * Interface for Wi-Fi score callback.
- *
- * @hide
- */
-oneway interface IScoreChangeCallback
-{
-    void onScoreChange(int sessionId, int score);
-
-    void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
-}
+/** {@hide} */
+parcelable BlobInfo;
\ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
new file mode 100644
index 0000000..9746dd0
--- /dev/null
+++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.blob;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class to provide information about a shared blob.
+ *
+ * @hide
+ */
+public final class BlobInfo implements Parcelable {
+    private final long mId;
+    private final long mExpiryTimeMs;
+    private final CharSequence mLabel;
+    private final List<AccessorInfo> mAccessors;
+
+    public BlobInfo(long id, long expiryTimeMs, CharSequence label,
+            List<AccessorInfo> accessors) {
+        mId = id;
+        mExpiryTimeMs = expiryTimeMs;
+        mLabel = label;
+        mAccessors = accessors;
+    }
+
+    private BlobInfo(Parcel in) {
+        mId = in.readLong();
+        mExpiryTimeMs = in.readLong();
+        mLabel = in.readCharSequence();
+        mAccessors = in.readArrayList(null /* classloader */);
+    }
+
+    public long getId() {
+        return mId;
+    }
+
+    public long getExpiryTimeMs() {
+        return mExpiryTimeMs;
+    }
+
+    public CharSequence getLabel() {
+        return mLabel;
+    }
+
+    public List<AccessorInfo> getAccessors() {
+        return Collections.unmodifiableList(mAccessors);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeLong(mId);
+        dest.writeLong(mExpiryTimeMs);
+        dest.writeCharSequence(mLabel);
+        dest.writeList(mAccessors);
+    }
+
+    @Override
+    public String toString() {
+        return toShortString();
+    }
+
+    private String toShortString() {
+        return "BlobInfo {"
+                + "id: " + mId + ","
+                + "expiryMs: " + mExpiryTimeMs + ","
+                + "label: " + mLabel + ","
+                + "accessors: " + AccessorInfo.toShortString(mAccessors) + ","
+                + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @NonNull
+    public static final Creator<BlobInfo> CREATOR = new Creator<BlobInfo>() {
+        @Override
+        @NonNull
+        public BlobInfo createFromParcel(Parcel source) {
+            return new BlobInfo(source);
+        }
+
+        @Override
+        @NonNull
+        public BlobInfo[] newArray(int size) {
+            return new BlobInfo[size];
+        }
+    };
+}
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
index d1e28e9..814ab6d 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobStoreManager.java
@@ -22,16 +22,19 @@
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
+import android.os.UserHandle;
 
 import com.android.internal.util.function.pooled.PooledLambda;
 
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -145,9 +148,6 @@
     /** @hide */
     public static final int INVALID_RES_ID = -1;
 
-    /** @hide */
-    public static final String DESC_RES_TYPE_STRING = "string";
-
     private final Context mContext;
     private final IBlobStoreManager mService;
 
@@ -215,7 +215,7 @@
     }
 
     /**
-     * Delete an existing session and any data that was written to that session so far.
+     * Abandons an existing session and deletes any data that was written to that session so far.
      *
      * @param sessionId a unique id obtained via {@link #createSession(BlobHandle)} that
      *                  represents a particular session.
@@ -224,9 +224,9 @@
      * @throws SecurityException when the caller does not own the session, or
      *                           the session does not exist or is invalid.
      */
-    public void deleteSession(@IntRange(from = 1) long sessionId) throws IOException {
+    public void abandonSession(@IntRange(from = 1) long sessionId) throws IOException {
         try {
-            mService.deleteSession(sessionId, mContext.getOpPackageName());
+            mService.abandonSession(sessionId, mContext.getOpPackageName());
         } catch (ParcelableException e) {
             e.maybeRethrow(IOException.class);
             throw new RuntimeException(e);
@@ -454,13 +454,13 @@
     }
 
     /**
-     * Release all active leases to the blob represented by {@code blobHandle} which are
+     * Release any active lease to the blob represented by {@code blobHandle} which is
      * currently held by the caller.
      *
      * @param blobHandle the {@link BlobHandle} representing the blob that the caller wants to
-     *                   release the leases for.
+     *                   release the lease for.
      *
-     * @throws IOException when there is an I/O error while releasing the releases to the blob.
+     * @throws IOException when there is an I/O error while releasing the release to the blob.
      * @throws SecurityException when the blob represented by the {@code blobHandle} does not
      *                           exist or the caller does not have access to it.
      * @throws IllegalArgumentException when {@code blobHandle} is invalid.
@@ -481,6 +481,7 @@
      *
      * @hide
      */
+    @TestApi
     public void waitForIdle(long timeoutMillis) throws InterruptedException, TimeoutException {
         try {
             final CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -495,6 +496,31 @@
         }
     }
 
+    /** @hide */
+    @NonNull
+    public List<BlobInfo> queryBlobsForUser(@NonNull UserHandle user) throws IOException {
+        try {
+            return mService.queryBlobsForUser(user.getIdentifier());
+        } catch (ParcelableException e) {
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /** @hide */
+    public void deleteBlob(@NonNull BlobInfo blobInfo) throws IOException {
+        try {
+            mService.deleteBlob(blobInfo.getId());
+        } catch (ParcelableException e) {
+            e.maybeRethrow(IOException.class);
+            throw new RuntimeException(e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /**
      * Represents an ongoing session of a blob's contribution to the blob store managed by the
      * system.
@@ -599,7 +625,7 @@
 
         /**
          * Close this session. It can be re-opened for writing/reading if it has not been
-         * abandoned (using {@link #abandon}) or closed (using {@link #commit}).
+         * abandoned (using {@link #abandon}) or committed (using {@link #commit}).
          *
          * @throws IOException when there is an I/O error while closing the session.
          * @throws SecurityException when the caller is not the owner of the session.
diff --git a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
index a85a25c..e783813 100644
--- a/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
+++ b/apex/blobstore/framework/java/android/app/blob/IBlobStoreManager.aidl
@@ -16,6 +16,7 @@
 package android.app.blob;
 
 import android.app.blob.BlobHandle;
+import android.app.blob.BlobInfo;
 import android.app.blob.IBlobStoreSession;
 import android.os.RemoteCallback;
 
@@ -24,11 +25,14 @@
     long createSession(in BlobHandle handle, in String packageName);
     IBlobStoreSession openSession(long sessionId, in String packageName);
     ParcelFileDescriptor openBlob(in BlobHandle handle, in String packageName);
-    void deleteSession(long sessionId, in String packageName);
+    void abandonSession(long sessionId, in String packageName);
 
     void acquireLease(in BlobHandle handle, int descriptionResId, in CharSequence description,
             long leaseTimeoutMillis, in String packageName);
     void releaseLease(in BlobHandle handle, in String packageName);
 
     void waitForIdle(in RemoteCallback callback);
+
+    List<BlobInfo> queryBlobsForUser(int userId);
+    void deleteBlob(long blobId);
 }
\ No newline at end of file
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 dab4797..970766d 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -15,7 +15,6 @@
  */
 package com.android.server.blob;
 
-import static android.app.blob.BlobStoreManager.DESC_RES_TYPE_STRING;
 import static android.app.blob.XmlTags.ATTR_DESCRIPTION;
 import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME;
 import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME;
@@ -30,16 +29,16 @@
 import static android.os.Process.INVALID_UID;
 import static android.system.OsConstants.O_RDONLY;
 
-import static com.android.server.blob.BlobStoreConfig.LOGV;
 import static com.android.server.blob.BlobStoreConfig.TAG;
 import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME;
 import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC;
+import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
+import static com.android.server.blob.BlobStoreUtils.getPackageResources;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.blob.BlobHandle;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.content.res.ResourceId;
 import android.content.res.Resources;
 import android.os.ParcelFileDescriptor;
@@ -65,6 +64,7 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.Objects;
+import java.util.function.Consumer;
 
 class BlobMetadata {
     private final Object mMetadataLock = new Object();
@@ -281,6 +281,10 @@
         return false;
     }
 
+    void forEachLeasee(Consumer<Leasee> consumer) {
+        mLeasees.forEach(consumer);
+    }
+
     File getBlobFile() {
         if (mBlobFile == null) {
             mBlobFile = BlobStoreConfig.getBlobFile(mBlobId);
@@ -506,16 +510,9 @@
             if (resources == null) {
                 return null;
             }
-            try {
-                final int resId = resources.getIdentifier(descriptionResEntryName,
-                        DESC_RES_TYPE_STRING, packageName);
-                return resId <= 0 ? null : resources.getString(resId);
-            } catch (Resources.NotFoundException e) {
-                if (LOGV) {
-                    Slog.w(TAG, "Description resource not found", e);
-                }
-                return null;
-            }
+            final int resId = getDescriptionResourceId(resources, descriptionResEntryName,
+                    packageName);
+            return resId == Resources.ID_NULL ? null : resources.getString(resId);
         }
 
         @Nullable
@@ -546,19 +543,6 @@
             return desc == null ? "<none>" : desc;
         }
 
-        @Nullable
-        private static Resources getPackageResources(@NonNull Context context,
-                @NonNull String packageName, int userId) {
-            try {
-                return context.getPackageManager()
-                        .getResourcesForApplicationAsUser(packageName, userId);
-            } catch (PackageManager.NameNotFoundException e) {
-                Slog.d(TAG, "Unknown package in user " + userId + ": "
-                        + packageName, e);
-                return null;
-            }
-        }
-
         void writeToXml(@NonNull XmlSerializer out) throws IOException {
             XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName);
             XmlUtils.writeIntAttribute(out, ATTR_UID, uid);
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 96f7b7a..53a97ce 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -36,6 +36,8 @@
 import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID;
 import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_VALID;
 import static com.android.server.blob.BlobStoreSession.stateToString;
+import static com.android.server.blob.BlobStoreUtils.getDescriptionResourceId;
+import static com.android.server.blob.BlobStoreUtils.getPackageResources;
 
 import android.annotation.CurrentTimeSecondsLong;
 import android.annotation.IdRes;
@@ -43,7 +45,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.blob.AccessorInfo;
 import android.app.blob.BlobHandle;
+import android.app.blob.BlobInfo;
 import android.app.blob.IBlobStoreManager;
 import android.app.blob.IBlobStoreSession;
 import android.content.BroadcastReceiver;
@@ -100,6 +104,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.nio.charset.StandardCharsets;
 import java.security.SecureRandom;
 import java.util.ArrayList;
@@ -110,6 +115,7 @@
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -343,7 +349,7 @@
         return session;
     }
 
-    private void deleteSessionInternal(long sessionId,
+    private void abandonSessionInternal(long sessionId,
             int callingUid, String callingPackage) {
         synchronized (mBlobsLock) {
             final BlobStoreSession session = openSessionInternal(sessionId,
@@ -351,7 +357,7 @@
             session.open();
             session.abandon();
             if (LOGV) {
-                Slog.v(TAG, "Deleted session with id " + sessionId
+                Slog.v(TAG, "Abandoned session with id " + sessionId
                         + "; callingUid=" + callingUid + ", callingPackage=" + callingPackage);
             }
             writeBlobSessionsAsync();
@@ -434,6 +440,48 @@
         }
     }
 
+    private List<BlobInfo> queryBlobsForUserInternal(int userId) {
+        final ArrayList<BlobInfo> blobInfos = new ArrayList<>();
+        synchronized (mBlobsLock) {
+            final ArrayMap<String, WeakReference<Resources>> resources = new ArrayMap<>();
+            final Function<String, Resources> resourcesGetter = (packageName) -> {
+                final WeakReference<Resources> resourcesRef = resources.get(packageName);
+                Resources packageResources = resourcesRef == null ? null : resourcesRef.get();
+                if (packageResources == null) {
+                    packageResources = getPackageResources(mContext, packageName, userId);
+                    resources.put(packageName, new WeakReference<>(packageResources));
+                }
+                return packageResources;
+            };
+            getUserBlobsLocked(userId).forEach((blobHandle, blobMetadata) -> {
+                final ArrayList<AccessorInfo> accessorInfos = new ArrayList<>();
+                blobMetadata.forEachLeasee(leasee -> {
+                    final int descriptionResId = leasee.descriptionResEntryName == null
+                            ? Resources.ID_NULL
+                            : getDescriptionResourceId(resourcesGetter.apply(leasee.packageName),
+                                    leasee.descriptionResEntryName, leasee.packageName);
+                    accessorInfos.add(new AccessorInfo(leasee.packageName, leasee.expiryTimeMillis,
+                            descriptionResId, leasee.description));
+                });
+                blobInfos.add(new BlobInfo(blobMetadata.getBlobId(),
+                        blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), accessorInfos));
+            });
+        }
+        return blobInfos;
+    }
+
+    private void deleteBlobInternal(long blobId, int callingUid) {
+        synchronized (mBlobsLock) {
+            final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(
+                    UserHandle.getUserId(callingUid));
+            userBlobs.entrySet().removeIf(entry -> {
+                final BlobMetadata blobMetadata = entry.getValue();
+                return blobMetadata.getBlobId() == blobId;
+            });
+            writeBlobsInfoAsync();
+        }
+    }
+
     private void verifyCallingPackage(int callingUid, String callingPackage) {
         if (mPackageManagerInternal.getPackageUid(
                 callingPackage, 0, UserHandle.getUserId(callingUid)) != callingUid) {
@@ -1167,7 +1215,7 @@
         }
 
         @Override
-        public void deleteSession(@IntRange(from = 1) long sessionId,
+        public void abandonSession(@IntRange(from = 1) long sessionId,
                 @NonNull String packageName) {
             Preconditions.checkArgumentPositive(sessionId,
                     "sessionId must be positive: " + sessionId);
@@ -1176,7 +1224,7 @@
             final int callingUid = Binder.getCallingUid();
             verifyCallingPackage(callingUid, packageName);
 
-            deleteSessionInternal(sessionId, callingUid, packageName);
+            abandonSessionInternal(sessionId, callingUid, packageName);
         }
 
         @Override
@@ -1250,6 +1298,28 @@
         }
 
         @Override
+        @NonNull
+        public List<BlobInfo> queryBlobsForUser(@UserIdInt int userId) {
+            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                throw new SecurityException("Only system uid is allowed to call "
+                        + "queryBlobsForUser()");
+            }
+
+            return queryBlobsForUserInternal(userId);
+        }
+
+        @Override
+        public void deleteBlob(long blobId) {
+            final int callingUid = Binder.getCallingUid();
+            if (callingUid != Process.SYSTEM_UID) {
+                throw new SecurityException("Only system uid is allowed to call "
+                        + "deleteBlob()");
+            }
+
+            deleteBlobInternal(blobId, callingUid);
+        }
+
+        @Override
         public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
                 @Nullable String[] args) {
             // TODO: add proto-based version of this.
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
new file mode 100644
index 0000000..6af540a
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.blob;
+
+import static com.android.server.blob.BlobStoreConfig.TAG;
+
+import android.annotation.IdRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.util.Slog;
+
+class BlobStoreUtils {
+    private static final String DESC_RES_TYPE_STRING = "string";
+
+    @Nullable
+    static Resources getPackageResources(@NonNull Context context,
+            @NonNull String packageName, int userId) {
+        try {
+            return context.getPackageManager()
+                    .getResourcesForApplicationAsUser(packageName, userId);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.d(TAG, "Unknown package in user " + userId + ": "
+                    + packageName, e);
+            return null;
+        }
+    }
+
+    @IdRes
+    static int getDescriptionResourceId(@NonNull Resources resources,
+            @NonNull String resourceEntryName, @NonNull String packageName) {
+        return resources.getIdentifier(resourceEntryName, DESC_RES_TYPE_STRING, packageName);
+    }
+}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 0d163cf..aedba29 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -40,7 +40,7 @@
      * @return the runtime permissions read
      */
     @Nullable
-    RuntimePermissionsState readAsUser(@NonNull UserHandle user);
+    RuntimePermissionsState readForUser(@NonNull UserHandle user);
 
     /**
      * Write the runtime permissions to persistence.
@@ -50,7 +50,8 @@
      * @param runtimePermissions the runtime permissions to write
      * @param user the user to write for
      */
-    void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
+    void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
+            @NonNull UserHandle user);
 
     /**
      * Delete the runtime permissions from persistence.
@@ -59,7 +60,7 @@
      *
      * @param user the user to delete for
      */
-    void deleteAsUser(@NonNull UserHandle user);
+    void deleteForUser(@NonNull UserHandle user);
 
     /**
      * Create a new instance of {@link RuntimePermissionsPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 30a8b45..e43f59a 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ApexContext;
+import android.content.ApexEnvironment;
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.util.ArrayMap;
@@ -67,7 +67,7 @@
 
     @Nullable
     @Override
-    public RuntimePermissionsState readAsUser(@NonNull UserHandle user) {
+    public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
         File file = getFile(user);
         try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
             XmlPullParser parser = Xml.newPullParser();
@@ -172,7 +172,7 @@
     }
 
     @Override
-    public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions,
+    public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
             @NonNull UserHandle user) {
         File file = getFile(user);
         AtomicFile atomicFile = new AtomicFile(file);
@@ -252,14 +252,14 @@
     }
 
     @Override
-    public void deleteAsUser(@NonNull UserHandle user) {
+    public void deleteForUser(@NonNull UserHandle user) {
         getFile(user).delete();
     }
 
     @NonNull
     private static File getFile(@NonNull UserHandle user) {
-        ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
-        File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
+        ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+        File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
         return new File(dataDirectory, RUNTIME_PERMISSIONS_FILE_NAME);
     }
 }
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
index cd2750a..c6bfc6d 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
@@ -23,6 +23,7 @@
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * State of all runtime permissions.
@@ -61,6 +62,14 @@
     @NonNull
     private final Map<String, List<PermissionState>> mSharedUserPermissions;
 
+    /**
+     * Create a new instance of this class.
+     *
+     * @param version the version of the runtime permissions
+     * @param fingerprint the fingerprint of the runtime permissions
+     * @param packagePermissions the runtime permissions by packages
+     * @param sharedUserPermissions the runtime permissions by shared users
+     */
     public RuntimePermissionsState(int version, @Nullable String fingerprint,
             @NonNull Map<String, List<PermissionState>> packagePermissions,
             @NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
@@ -70,32 +79,72 @@
         mSharedUserPermissions = sharedUserPermissions;
     }
 
+    /**
+     * Get the version of the runtime permissions.
+     *
+     * @return the version of the runtime permissions
+     */
     public int getVersion() {
         return mVersion;
     }
 
+    /**
+     * Get the fingerprint of the runtime permissions.
+     *
+     * @return the fingerprint of the runtime permissions
+     */
     @Nullable
     public String getFingerprint() {
         return mFingerprint;
     }
 
+    /**
+     * Get the runtime permissions by packages.
+     *
+     * @return the runtime permissions by packages
+     */
     @NonNull
     public Map<String, List<PermissionState>> getPackagePermissions() {
         return mPackagePermissions;
     }
 
+    /**
+     * Get the runtime permissions by shared users.
+     *
+     * @return the runtime permissions by shared users
+     */
     @NonNull
     public Map<String, List<PermissionState>> getSharedUserPermissions() {
         return mSharedUserPermissions;
     }
 
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object == null || getClass() != object.getClass()) {
+            return false;
+        }
+        RuntimePermissionsState that = (RuntimePermissionsState) object;
+        return mVersion == that.mVersion
+                && Objects.equals(mFingerprint, that.mFingerprint)
+                && Objects.equals(mPackagePermissions, that.mPackagePermissions)
+                && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
+    }
+
     /**
      * State of a single permission.
      */
-    public static class PermissionState {
+    public static final class PermissionState {
 
         /**
-         * Name of the permission.
+         * The name of the permission.
          */
         @NonNull
         private final String mName;
@@ -106,27 +155,68 @@
         private final boolean mGranted;
 
         /**
-         * Flags of the permission.
+         * The flags of the permission.
          */
         private final int mFlags;
 
+        /**
+         * Create a new instance of this class.
+         *
+         * @param name the name of the permission
+         * @param granted whether the permission is granted
+         * @param flags the flags of the permission
+         */
         public PermissionState(@NonNull String name, boolean granted, int flags) {
             mName = name;
             mGranted = granted;
             mFlags = flags;
         }
 
+        /**
+         * Get the name of the permission.
+         *
+         * @return the name of the permission
+         */
         @NonNull
         public String getName() {
             return mName;
         }
 
+        /**
+         * Get whether the permission is granted.
+         *
+         * @return whether the permission is granted
+         */
         public boolean isGranted() {
             return mGranted;
         }
 
+        /**
+         * Get the flags of the permission.
+         *
+         * @return the flags of the permission
+         */
         public int getFlags() {
             return mFlags;
         }
+
+        @Override
+        public boolean equals(Object object) {
+            if (this == object) {
+                return true;
+            }
+            if (object == null || getClass() != object.getClass()) {
+                return false;
+            }
+            PermissionState that = (PermissionState) object;
+            return mGranted == that.mGranted
+                    && mFlags == that.mFlags
+                    && Objects.equals(mName, that.mName);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mName, mGranted, mFlags);
+        }
     }
 }
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 64d6545..2e5a28a 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -40,7 +40,7 @@
      * @return the roles read
      */
     @Nullable
-    RolesState readAsUser(@NonNull UserHandle user);
+    RolesState readForUser(@NonNull UserHandle user);
 
     /**
      * Write the roles to persistence.
@@ -50,7 +50,7 @@
      * @param roles the roles to write
      * @param user the user to write for
      */
-    void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user);
+    void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
 
     /**
      * Delete the roles from persistence.
@@ -59,7 +59,7 @@
      *
      * @param user the user to delete for
      */
-    void deleteAsUser(@NonNull UserHandle user);
+    void deleteForUser(@NonNull UserHandle user);
 
     /**
      * Create a new instance of {@link RolesPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 3031c82..f66257f 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ApexContext;
+import android.content.ApexEnvironment;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -65,7 +65,7 @@
 
     @Nullable
     @Override
-    public RolesState readAsUser(@NonNull UserHandle user) {
+    public RolesState readForUser(@NonNull UserHandle user) {
         File file = getFile(user);
         try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
             XmlPullParser parser = Xml.newPullParser();
@@ -146,7 +146,7 @@
     }
 
     @Override
-    public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) {
+    public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
         File file = getFile(user);
         AtomicFile atomicFile = new AtomicFile(file);
         FileOutputStream outputStream = null;
@@ -205,14 +205,14 @@
     }
 
     @Override
-    public void deleteAsUser(@NonNull UserHandle user) {
+    public void deleteForUser(@NonNull UserHandle user) {
         getFile(user).delete();
     }
 
     @NonNull
     private static File getFile(@NonNull UserHandle user) {
-        ApexContext apexContext = ApexContext.getApexContext(APEX_MODULE_NAME);
-        File dataDirectory = apexContext.getDeviceProtectedDataDirForUser(user);
+        ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment(APEX_MODULE_NAME);
+        File dataDirectory = apexEnvironment.getDeviceProtectedDataDirForUser(user);
         return new File(dataDirectory, ROLES_FILE_NAME);
     }
 }
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
index 7da9d11..f61efa0 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesState.java
@@ -22,6 +22,7 @@
 import android.annotation.SystemApi.Client;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -50,6 +51,13 @@
     @NonNull
     private final Map<String, Set<String>> mRoles;
 
+    /**
+     * Create a new instance of this class.
+     *
+     * @param version the version of the roles
+     * @param packagesHash the hash of all packages in the system
+     * @param roles the roles
+     */
     public RolesState(int version, @Nullable String packagesHash,
             @NonNull Map<String, Set<String>> roles) {
         mVersion = version;
@@ -57,17 +65,51 @@
         mRoles = roles;
     }
 
+    /**
+     * Get the version of the roles.
+     *
+     * @return the version of the roles
+     */
     public int getVersion() {
         return mVersion;
     }
 
+    /**
+     * Get the hash of all packages in the system.
+     *
+     * @return the hash of all packages in the system
+     */
     @Nullable
     public String getPackagesHash() {
         return mPackagesHash;
     }
 
+    /**
+     * Get the roles.
+     *
+     * @return the roles
+     */
     @NonNull
     public Map<String, Set<String>> getRoles() {
         return mRoles;
     }
+
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object == null || getClass() != object.getClass()) {
+            return false;
+        }
+        RolesState that = (RolesState) object;
+        return mVersion == that.mVersion
+                && Objects.equals(mPackagesHash, that.mPackagesHash)
+                && Objects.equals(mRoles, that.mRoles);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mVersion, mPackagesHash, mRoles);
+    }
 }
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index dc61f2ae..c84627d 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,6 +54,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -102,9 +103,6 @@
     private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
     private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
     private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
-    private final BroadcastReceiver mAppUpdateReceiver;
-    private final BroadcastReceiver mUserUpdateReceiver;
-    private final ShutdownEventReceiver mShutdownEventReceiver;
 
     private StatsManagerService mStatsManagerService;
 
@@ -118,27 +116,6 @@
         super();
         mContext = context;
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        mAppUpdateReceiver = new AppUpdateReceiver();
-        mUserUpdateReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                synchronized (sStatsdLock) {
-                    if (sStatsd == null) {
-                        Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
-                        return;
-                    }
-                    try {
-                        // Pull the latest state of UID->app name, version mapping.
-                        // Needed since the new user basically has a version of every app.
-                        informAllUidsLocked(context);
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
-                        forgetEverythingLocked();
-                    }
-                }
-            }
-        };
-        mShutdownEventReceiver = new ShutdownEventReceiver();
         if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
         HandlerThread handlerThread = new HandlerThread(TAG);
         handlerThread.start();
@@ -162,9 +139,18 @@
         return ret;
     }
 
-    // Assumes that sStatsdLock is held.
-    @GuardedBy("sStatsdLock")
-    private void informAllUidsLocked(Context context) throws RemoteException {
+    /**
+     * Non-blocking call to retrieve a reference to statsd
+     *
+     * @return IStatsd object if statsd is ready, null otherwise.
+     */
+    private static IStatsd getStatsdNonblocking() {
+        synchronized (sStatsdLock) {
+            return sStatsd;
+        }
+    }
+
+    private static void informAllUidsLocked(Context context) throws RemoteException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
         PackageManager pm = context.getPackageManager();
         final List<UserHandle> users = um.getUserHandles(true);
@@ -273,7 +259,6 @@
                         if (!replacing) {
                             // Don't bother sending an update if we're right about to get another
                             // intent for the new version that's added.
-                            PackageManager pm = context.getPackageManager();
                             String app = intent.getData().getSchemeSpecificPart();
                             sStatsd.informOnePackageRemoved(app, uid);
                         }
@@ -303,23 +288,43 @@
         }
     }
 
-    public final static class AnomalyAlarmListener implements OnAlarmListener {
+    private static final class UserUpdateReceiver extends BroadcastReceiver {
         @Override
-        public void onAlarm() {
-            Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
-                    + System.currentTimeMillis() + "ms.");
+        public void onReceive(Context context, Intent intent) {
             synchronized (sStatsdLock) {
                 if (sStatsd == null) {
-                    Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+                    Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
                     return;
                 }
                 try {
-                    // Two-way call to statsd to retain AlarmManager wakelock
-                    sStatsd.informAnomalyAlarmFired();
+                    // Pull the latest state of UID->app name, version mapping.
+                    // Needed since the new user basically has a version of every app.
+                    informAllUidsLocked(context);
                 } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+                    Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
                 }
             }
+        }
+    }
+
+    public static final class AnomalyAlarmListener implements OnAlarmListener {
+        @Override
+        public void onAlarm() {
+            if (DEBUG) {
+                Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+                        + System.currentTimeMillis() + "ms.");
+            }
+            IStatsd statsd = getStatsdNonblocking();
+            if (statsd == null) {
+                Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+                return;
+            }
+            try {
+                // Two-way call to statsd to retain AlarmManager wakelock
+                statsd.informAnomalyAlarmFired();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+            }
             // AlarmManager releases its own wakelock here.
         }
     }
@@ -330,17 +335,16 @@
             if (DEBUG) {
                 Log.d(TAG, "Time to poll something.");
             }
-            synchronized (sStatsdLock) {
-                if (sStatsd == null) {
-                    Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
-                    return;
-                }
-                try {
-                    // Two-way call to statsd to retain AlarmManager wakelock
-                    sStatsd.informPollAlarmFired();
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
-                }
+            IStatsd statsd = getStatsdNonblocking();
+            if (statsd == null) {
+                Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+                return;
+            }
+            try {
+                // Two-way call to statsd to retain AlarmManager wakelock
+                statsd.informPollAlarmFired();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
             }
         }
     }
@@ -351,17 +355,16 @@
             if (DEBUG) {
                 Log.d(TAG, "Time to trigger periodic alarm.");
             }
-            synchronized (sStatsdLock) {
-                if (sStatsd == null) {
-                    Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
-                    return;
-                }
-                try {
-                    // Two-way call to statsd to retain AlarmManager wakelock
-                    sStatsd.informAlarmForSubscriberTriggeringFired();
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
-                }
+            IStatsd statsd = getStatsdNonblocking();
+            if (statsd == null) {
+                Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+                return;
+            }
+            try {
+                // Two-way call to statsd to retain AlarmManager wakelock
+                statsd.informAlarmForSubscriberTriggeringFired();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
             }
             // AlarmManager releases its own wakelock here.
         }
@@ -379,17 +382,19 @@
                 return;
             }
 
-            Log.i(TAG, "StatsCompanionService noticed a shutdown.");
-            synchronized (sStatsdLock) {
-                if (sStatsd == null) {
-                    Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
-                    return;
-                }
-                try {
-                    sStatsd.informDeviceShutdown();
-                } catch (Exception e) {
-                    Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
-                }
+            if (DEBUG) {
+                Log.i(TAG, "StatsCompanionService noticed a shutdown.");
+            }
+            IStatsd statsd = getStatsdNonblocking();
+            if (statsd == null) {
+                Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
+                return;
+            }
+            try {
+                // two way binder call
+                statsd.informDeviceShutdown();
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
             }
         }
     }
@@ -515,7 +520,7 @@
         }
     }
 
-    @Override
+    @Override // Binder call
     public void triggerUidSnapshot() {
         StatsCompanion.enforceStatsdCallingUid();
         synchronized (sStatsdLock) {
@@ -525,7 +530,7 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to trigger uid snapshot.", e);
             } finally {
-                restoreCallingIdentity(token);
+                Binder.restoreCallingIdentity(token);
             }
         }
     }
@@ -539,15 +544,28 @@
     // Statsd related code
 
     /**
-     * Fetches the statsd IBinder service.
-     * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
-     * sStatsd with a null check.
+     * Fetches the statsd IBinder service. This is a blocking call.
+     * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
+     * the cached sStatsd via {@link #getStatsdNonblocking()}.
      */
-    private static IStatsd fetchStatsdService() {
-        return IStatsd.Stub.asInterface(StatsFrameworkInitializer
-            .getStatsServiceManager()
-            .getStatsdServiceRegisterer()
-            .get());
+    private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
+        synchronized (sStatsdLock) {
+            if (sStatsd == null) {
+                sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+                        .getStatsServiceManager()
+                        .getStatsdServiceRegisterer()
+                        .get());
+                if (sStatsd != null) {
+                    try {
+                        sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
+                        statsdNotReadyLocked();
+                    }
+                }
+            }
+            return sStatsd;
+        }
     }
 
     /**
@@ -567,67 +585,84 @@
      * statsd.
      */
     private void sayHiToStatsd() {
-        synchronized (sStatsdLock) {
-            if (sStatsd != null) {
-                Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
-                        new IllegalStateException(
-                                "sStatsd is not null when being fetched"));
-                return;
-            }
-            sStatsd = fetchStatsdService();
-            if (sStatsd == null) {
-                Log.i(TAG,
-                        "Could not yet find statsd to tell it that StatsCompanion is "
-                                + "alive.");
-                return;
-            }
-            mStatsManagerService.statsdReady(sStatsd);
-            if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+        if (getStatsdNonblocking() != null) {
+            Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
+                    new IllegalStateException(
+                            "sStatsd is not null when being fetched"));
+            return;
+        }
+        StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
+        IStatsd statsd = fetchStatsdService(deathRecipient);
+        if (statsd == null) {
+            Log.i(TAG,
+                    "Could not yet find statsd to tell it that StatsCompanion is "
+                            + "alive.");
+            return;
+        }
+        mStatsManagerService.statsdReady(statsd);
+        if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+        try {
+            statsd.statsCompanionReady();
+
+            cancelAnomalyAlarm();
+            cancelPullingAlarm();
+
+            BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
+            BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
+            BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
+
+            // Setup broadcast receiver for updates.
+            IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
+
+            // Setup receiver for user initialize (which happens once for a new user)
+            // and
+            // if a user is removed.
+            filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
+            filter.addAction(Intent.ACTION_USER_REMOVED);
+            mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
+
+            // Setup receiver for device reboots or shutdowns.
+            filter = new IntentFilter(Intent.ACTION_REBOOT);
+            filter.addAction(Intent.ACTION_SHUTDOWN);
+            mContext.registerReceiverForAllUsers(
+                    shutdownEventReceiver, filter, null, null);
+
+            // Only add the receivers if the registration is successful.
+            deathRecipient.addRegisteredBroadcastReceivers(
+                    List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+
+            final long token = Binder.clearCallingIdentity();
             try {
-                sStatsd.statsCompanionReady();
-                // If the statsCompanionReady two-way binder call returns, link to statsd.
-                try {
-                    sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
-                    forgetEverythingLocked();
-                }
-                // Setup broadcast receiver for updates.
-                IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
-                filter.addAction(Intent.ACTION_PACKAGE_ADDED);
-                filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-                filter.addDataScheme("package");
-                mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
-
-                // Setup receiver for user initialize (which happens once for a new user)
-                // and
-                // if a user is removed.
-                filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
-                filter.addAction(Intent.ACTION_USER_REMOVED);
-                mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
-
-                // Setup receiver for device reboots or shutdowns.
-                filter = new IntentFilter(Intent.ACTION_REBOOT);
-                filter.addAction(Intent.ACTION_SHUTDOWN);
-                mContext.registerReceiverForAllUsers(
-                        mShutdownEventReceiver, filter, null, null);
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    // Pull the latest state of UID->app name, version mapping when
-                    // statsd starts.
-                    informAllUidsLocked(mContext);
-                } finally {
-                    restoreCallingIdentity(token);
-                }
-                Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
-                forgetEverythingLocked();
+                // Pull the latest state of UID->app name, version mapping when
+                // statsd starts.
+                informAllUidsLocked(mContext);
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
+            Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
         }
     }
 
     private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+
+        private List<BroadcastReceiver> mReceiversToUnregister;
+
+        StatsdDeathRecipient() {
+            mReceiversToUnregister = new ArrayList<>();
+        }
+
+        public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
+            synchronized (sStatsdLock) {
+                mReceiversToUnregister.addAll(receivers);
+            }
+        }
+
         @Override
         public void binderDied() {
             Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -656,20 +691,18 @@
                         }
                     }
                 }
-                forgetEverythingLocked();
+                // We only unregister in binder death becaseu receivers can only be unregistered
+                // once, or an IllegalArgumentException is thrown.
+                for (BroadcastReceiver receiver: mReceiversToUnregister) {
+                    mContext.unregisterReceiver(receiver);
+                }
+                statsdNotReadyLocked();
             }
         }
     }
 
-    @GuardedBy("StatsCompanionService.sStatsdLock")
-    private void forgetEverythingLocked() {
+    private void statsdNotReadyLocked() {
         sStatsd = null;
-        mContext.unregisterReceiver(mAppUpdateReceiver);
-        mContext.unregisterReceiver(mUserUpdateReceiver);
-        mContext.unregisterReceiver(mShutdownEventReceiver);
-        cancelAnomalyAlarm();
-        cancelPullingAlarm();
-
         mStatsManagerService.statsdNotReady();
     }
 
diff --git a/api/current.txt b/api/current.txt
index 59afab2..2efb305 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4368,7 +4368,7 @@
     method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
     method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
     method @Nullable public static String permissionToOp(@NonNull String);
-    method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+    method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
     method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
     method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
     method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -4424,14 +4424,6 @@
     field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
   }
 
-  public abstract static class AppOpsManager.AppOpsCollector {
-    ctor public AppOpsManager.AppOpsCollector();
-    method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
-    method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
-    method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
-    method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
-  }
-
   public static interface AppOpsManager.OnOpActiveChangedListener {
     method public void onOpActiveChanged(@NonNull String, int, @NonNull String, boolean);
   }
@@ -4440,6 +4432,13 @@
     method public void onOpChanged(String, String);
   }
 
+  public abstract static class AppOpsManager.OnOpNotedCallback {
+    ctor public AppOpsManager.OnOpNotedCallback();
+    method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
+    method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
+    method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
+  }
+
   public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
     ctor public Application();
     method public static String getProcessName();
@@ -4591,7 +4590,7 @@
     method @NonNull public String getMessage();
     method @IntRange(from=0) public int getNotingUid();
     method @NonNull public String getOp();
-    method @IntRange(from=0) public long getTime();
+    method public long getTime();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
   }
@@ -7583,12 +7582,12 @@
   }
 
   public class BlobStoreManager {
+    method public void abandonSession(@IntRange(from=1) long) throws java.io.IOException;
     method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int, long) throws java.io.IOException;
     method public void acquireLease(@NonNull android.app.blob.BlobHandle, @NonNull CharSequence, long) throws java.io.IOException;
     method public void acquireLease(@NonNull android.app.blob.BlobHandle, @IdRes int) throws java.io.IOException;
     method public void acquireLease(@NonNull android.app.blob.BlobHandle, @NonNull CharSequence) throws java.io.IOException;
     method @IntRange(from=1) public long createSession(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
-    method public void deleteSession(@IntRange(from=1) long) throws java.io.IOException;
     method @NonNull public android.os.ParcelFileDescriptor openBlob(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
     method @NonNull public android.app.blob.BlobStoreManager.Session openSession(@IntRange(from=1) long) throws java.io.IOException;
     method public void releaseLease(@NonNull android.app.blob.BlobHandle) throws java.io.IOException;
@@ -9467,7 +9466,7 @@
   public static final class WifiDeviceFilter.Builder {
     ctor public WifiDeviceFilter.Builder();
     method @NonNull public android.companion.WifiDeviceFilter build();
-    method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@Nullable android.net.MacAddress);
+    method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@NonNull android.net.MacAddress);
     method @NonNull public android.companion.WifiDeviceFilter.Builder setBssidMask(@NonNull android.net.MacAddress);
     method @NonNull public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
   }
@@ -9882,7 +9881,7 @@
     method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
     method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
     method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
-    method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+    method public void notifyChange(@NonNull java.util.Collection<android.net.Uri>, @Nullable android.database.ContentObserver, int);
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -10566,6 +10565,7 @@
     field public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
     field public static final String ACTION_ASSIST = "android.intent.action.ASSIST";
     field public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+    field public static final String ACTION_AUTO_REVOKE_PERMISSIONS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
     field public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
     field public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
     field public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -12972,11 +12972,11 @@
     method @Deprecated public final void dispatchChange(boolean);
     method public final void dispatchChange(boolean, @Nullable android.net.Uri);
     method public final void dispatchChange(boolean, @Nullable android.net.Uri, int);
-    method public final void dispatchChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+    method public final void dispatchChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
     method public void onChange(boolean);
     method public void onChange(boolean, @Nullable android.net.Uri);
     method public void onChange(boolean, @Nullable android.net.Uri, int);
-    method public void onChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+    method public void onChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
   }
 
   public interface CrossProcessCursor extends android.database.Cursor {
@@ -18118,9 +18118,7 @@
     ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
     ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
     ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
-    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull android.security.identity.IdentityCredential);
     method @Deprecated public javax.crypto.Cipher getCipher();
-    method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
     method @Deprecated public javax.crypto.Mac getMac();
     method @Deprecated public java.security.Signature getSignature();
   }
@@ -27055,7 +27053,8 @@
     method public void registerRouteCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.RouteCallback, @NonNull android.media.RouteDiscoveryPreference);
     method public void registerTransferCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.TransferCallback);
     method public void setOnGetControllerHintsListener(@Nullable android.media.MediaRouter2.OnGetControllerHintsListener);
-    method public void transferTo(@Nullable android.media.MediaRoute2Info);
+    method public void stop();
+    method public void transferTo(@NonNull android.media.MediaRoute2Info);
     method public void unregisterControllerCallback(@NonNull android.media.MediaRouter2.ControllerCallback);
     method public void unregisterRouteCallback(@NonNull android.media.MediaRouter2.RouteCallback);
     method public void unregisterTransferCallback(@NonNull android.media.MediaRouter2.TransferCallback);
@@ -27095,8 +27094,9 @@
 
   public abstract static class MediaRouter2.TransferCallback {
     ctor public MediaRouter2.TransferCallback();
+    method public void onStopped(@NonNull android.media.MediaRouter2.RoutingController);
     method public void onTransferFailed(@NonNull android.media.MediaRoute2Info);
-    method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @Nullable android.media.MediaRouter2.RoutingController);
+    method public void onTransferred(@NonNull android.media.MediaRouter2.RoutingController, @NonNull android.media.MediaRouter2.RoutingController);
   }
 
   public class MediaScannerConnection implements android.content.ServiceConnection {
@@ -36154,6 +36154,8 @@
     method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
     method public static boolean isExternalStorageLegacy();
     method public static boolean isExternalStorageLegacy(@NonNull java.io.File);
+    method public static boolean isExternalStorageManager();
+    method public static boolean isExternalStorageManager(@NonNull java.io.File);
     method public static boolean isExternalStorageRemovable();
     method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
     field public static String DIRECTORY_ALARMS;
@@ -42690,7 +42692,7 @@
     ctor public PersonalizationData.Builder();
     method @NonNull public android.security.identity.PersonalizationData.Builder addAccessControlProfile(@NonNull android.security.identity.AccessControlProfile);
     method @NonNull public android.security.identity.PersonalizationData build();
-    method @NonNull public android.security.identity.PersonalizationData.Builder setEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
+    method @NonNull public android.security.identity.PersonalizationData.Builder putEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
   }
 
   public abstract class ResultData {
@@ -42698,7 +42700,7 @@
     method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String);
     method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
     method @Nullable public abstract byte[] getMessageAuthenticationCode();
-    method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaceNames();
+    method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaces();
     method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
     method @NonNull public abstract byte[] getStaticAuthenticationData();
     method public abstract int getStatus(@NonNull String, @NonNull String);
@@ -43110,7 +43112,7 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method @NonNull public android.service.autofill.FillResponse.Builder addDataset(@Nullable android.service.autofill.Dataset);
-    method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlinePresentation);
+    method @NonNull public android.service.autofill.FillResponse.Builder addInlineAction(@NonNull android.service.autofill.InlineAction);
     method @NonNull public android.service.autofill.FillResponse build();
     method @NonNull public android.service.autofill.FillResponse.Builder disableAutofill(long);
     method @NonNull public android.service.autofill.FillResponse.Builder setAuthentication(@NonNull android.view.autofill.AutofillId[], @Nullable android.content.IntentSender, @Nullable android.widget.RemoteViews);
@@ -43140,6 +43142,15 @@
     method public android.service.autofill.ImageTransformation build();
   }
 
+  public final class InlineAction implements android.os.Parcelable {
+    ctor public InlineAction(@NonNull android.service.autofill.InlinePresentation, @NonNull android.content.IntentSender);
+    method public int describeContents();
+    method @NonNull public android.content.IntentSender getAction();
+    method @NonNull public android.service.autofill.InlinePresentation getInlinePresentation();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.InlineAction> CREATOR;
+  }
+
   public final class InlinePresentation implements android.os.Parcelable {
     ctor public InlinePresentation(@NonNull android.app.slice.Slice, @NonNull android.view.inline.InlinePresentationSpec, boolean);
     method public int describeContents();
@@ -46585,12 +46596,9 @@
     field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
     field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
     field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
-    field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
-    field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int";
     field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
     field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
     field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
-    field public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
     field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
     field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
     field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
@@ -46783,7 +46791,6 @@
     field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
     field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool";
     field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
-    field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
     field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
     field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool";
     field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -47563,7 +47570,6 @@
     method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method public int getDomain();
-    method public int getNrState();
     method @Nullable public String getRegisteredPlmn();
     method public int getTransportType();
     method public boolean isRegistered();
@@ -47766,9 +47772,7 @@
     method public boolean getIsManualSelection();
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
     method public String getOperatorAlphaLong();
-    method @Nullable public String getOperatorAlphaLongRaw();
     method public String getOperatorAlphaShort();
-    method @Nullable public String getOperatorAlphaShortRaw();
     method public String getOperatorNumeric();
     method public boolean getRoaming();
     method public int getState();
@@ -56157,7 +56161,7 @@
   }
 
   public static final class AccessibilityNodeInfo.ExtraRenderingInfo {
-    method @Nullable public android.util.Size getLayoutParams();
+    method @Nullable public android.util.Size getLayoutSize();
     method public float getTextSizeInPx();
     method public int getTextSizeUnit();
   }
@@ -57991,7 +57995,7 @@
     method @Deprecated public abstract void removeSessionCookie();
     method public abstract void removeSessionCookies(@Nullable android.webkit.ValueCallback<java.lang.Boolean>);
     method public abstract void setAcceptCookie(boolean);
-    method public static void setAcceptFileSchemeCookies(boolean);
+    method @Deprecated public static void setAcceptFileSchemeCookies(boolean);
     method public abstract void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
     method public abstract void setCookie(String, String);
     method public abstract void setCookie(String, String, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
@@ -58356,8 +58360,8 @@
     method public abstract String getUserAgentString();
     method public abstract void setAllowContentAccess(boolean);
     method public abstract void setAllowFileAccess(boolean);
-    method public abstract void setAllowFileAccessFromFileURLs(boolean);
-    method public abstract void setAllowUniversalAccessFromFileURLs(boolean);
+    method @Deprecated public abstract void setAllowFileAccessFromFileURLs(boolean);
+    method @Deprecated public abstract void setAllowUniversalAccessFromFileURLs(boolean);
     method public abstract void setAppCacheEnabled(boolean);
     method @Deprecated public abstract void setAppCacheMaxSize(long);
     method public abstract void setAppCachePath(String);
@@ -82223,4 +82227,3 @@
   }
 
 }
-
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 6863221..69b52693 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -47,6 +47,7 @@
     method @NonNull public String[] getTetheredIfaces();
     method @NonNull public String[] getTetheringErroredIfaces();
     method public boolean isTetheringSupported();
+    method public boolean isTetheringSupported(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
     method @RequiresPermission(anyOf={"android.permission.TETHER_PRIVILEGED", android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
     method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
@@ -86,6 +87,9 @@
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+    field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+    field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+    field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
   }
 
   public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -102,6 +106,7 @@
     ctor public TetheringManager.TetheringEventCallback();
     method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
     method public void onError(@NonNull String, int);
+    method public void onOffloadStatusChanged(int);
     method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
     method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
     method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
diff --git a/api/removed.txt b/api/removed.txt
index fb6d576..8537b21 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -69,6 +69,10 @@
 
 package android.content {
 
+  public abstract class ContentResolver {
+    method @Deprecated public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+  }
+
   public abstract class Context {
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 0c44600..143fa7b 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -231,6 +231,7 @@
     field public static final String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
     field public static final String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
     field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
+    field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
     field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
     field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
@@ -388,6 +389,7 @@
     field public static final String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
     field public static final String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
     field public static final String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
+    field public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = "android:auto_revoke_permissions_if_unused";
     field public static final String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
     field public static final String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
     field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
@@ -1758,8 +1760,8 @@
 
 package android.content {
 
-  public class ApexContext {
-    method @NonNull public static android.content.ApexContext getApexContext(@NonNull String);
+  public class ApexEnvironment {
+    method @NonNull public static android.content.ApexEnvironment getApexEnvironment(@NonNull String);
     method @NonNull public java.io.File getCredentialProtectedDataDirForUser(@NonNull android.os.UserHandle);
     method @NonNull public java.io.File getDeviceProtectedDataDir();
     method @NonNull public java.io.File getDeviceProtectedDataDirForUser(@NonNull android.os.UserHandle);
@@ -2014,7 +2016,6 @@
   }
 
   public final class InstallationFile {
-    ctor public InstallationFile(int, @NonNull String, long, @Nullable byte[], @Nullable byte[]);
     method public long getLengthBytes();
     method public int getLocation();
     method @Nullable public byte[] getMetadata();
@@ -2216,9 +2217,7 @@
     field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
     field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
     field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
-    field public static final int FLAG_PERMISSION_AUTO_REVOKED = 1048576; // 0x100000
-    field public static final int FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED = 131072; // 0x20000
-    field public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 262144; // 0x40000
+    field public static final int FLAG_PERMISSION_AUTO_REVOKED = 131072; // 0x20000
     field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
     field public static final int FLAG_PERMISSION_GRANTED_BY_ROLE = 32768; // 0x8000
     field public static final int FLAG_PERMISSION_ONE_TIME = 65536; // 0x10000
@@ -2302,7 +2301,7 @@
     method public void onPermissionsChanged(int);
   }
 
-  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKE_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+  @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT, android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME, android.content.pm.PackageManager.FLAG_PERMISSION_AUTO_REVOKED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
   }
 
   public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -2940,7 +2939,7 @@
 
   public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
-    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
   }
 
   public final class LightsRequest {
@@ -4987,7 +4986,7 @@
 
 package android.media.tv.tuner.filter {
 
-  public class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+  public final class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.AlpFilterConfiguration.Builder builder(@NonNull android.content.Context);
     method public int getLengthType();
     method public int getPacketType();
@@ -5002,10 +5001,11 @@
     field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
   }
 
-  public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
+  public static final class AlpFilterConfiguration.Builder {
     method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration build();
     method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setLengthType(int);
     method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setPacketType(int);
+    method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
   }
 
   public class AudioDescriptor {
@@ -5093,15 +5093,11 @@
     method public abstract int getType();
   }
 
-  public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
-    method @NonNull public T setSettings(@Nullable android.media.tv.tuner.filter.Settings);
-  }
-
   public abstract class FilterEvent {
     ctor public FilterEvent();
   }
 
-  public class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+  public final class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder(@NonNull android.content.Context);
     method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
     method public int getDstPort();
@@ -5111,11 +5107,12 @@
     method public boolean isPassthrough();
   }
 
-  public static class IpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.IpFilterConfiguration.Builder> {
+  public static final class IpFilterConfiguration.Builder {
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
+    method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
     method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcPort(int);
   }
@@ -5139,15 +5136,16 @@
     method public boolean isSecureMemory();
   }
 
-  public class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+  public final class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder builder(@NonNull android.content.Context);
     method public int getMmtpPacketId();
     method public int getType();
   }
 
-  public static class MmtpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder> {
+  public static final class MmtpFilterConfiguration.Builder {
     method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration build();
     method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setMmtpPacketId(int);
+    method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
   }
 
   public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5282,7 +5280,7 @@
     field public static final long TIMESTAMP_UNAVAILABLE = -1L; // 0xffffffffffffffffL
   }
 
-  public class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+  public final class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TlvFilterConfiguration.Builder builder(@NonNull android.content.Context);
     method public int getPacketType();
     method public int getType();
@@ -5295,21 +5293,23 @@
     field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
   }
 
-  public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
+  public static final class TlvFilterConfiguration.Builder {
     method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration build();
     method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setCompressedIpPacket(boolean);
     method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPacketType(int);
     method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPassthrough(boolean);
+    method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
   }
 
-  public class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+  public final class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder(@NonNull android.content.Context);
     method public int getTpid();
     method public int getType();
   }
 
-  public static class TsFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TsFilterConfiguration.Builder> {
+  public static final class TsFilterConfiguration.Builder {
     method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build();
+    method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
     method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int);
   }
 
@@ -6128,7 +6128,7 @@
   }
 
   public class EthernetManager {
-    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
   }
 
   public static interface EthernetManager.TetheredInterfaceCallback {
@@ -6594,6 +6594,9 @@
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+    field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+    field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+    field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
   }
 
   public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -6610,6 +6613,7 @@
     ctor public TetheringManager.TetheringEventCallback();
     method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
     method public void onError(@NonNull String, int);
+    method public void onOffloadStatusChanged(int);
     method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
     method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
     method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
@@ -7325,17 +7329,17 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset();
+    method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
-    method @Nullable @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public String getCountryCode();
+    method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
     method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
     method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
     method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
-    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+    method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
@@ -7456,9 +7460,9 @@
     method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
   }
 
-  public static interface WifiManager.ScoreChangeCallback {
-    method public void onScoreChange(int, int);
-    method public void onTriggerUpdateOfWifiUsabilityStats(int);
+  public static interface WifiManager.ScoreUpdateObserver {
+    method public void notifyScoreUpdate(int, int);
+    method public void triggerUpdateOfWifiUsabilityStats(int);
   }
 
   public static interface WifiManager.SoftApCallback {
@@ -7478,9 +7482,9 @@
   }
 
   public static interface WifiManager.WifiConnectedNetworkScorer {
-    method public void setScoreChangeCallback(@NonNull android.net.wifi.WifiManager.ScoreChangeCallback);
-    method public void start(int);
-    method public void stop(int);
+    method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
+    method public void onStart(int);
+    method public void onStop(int);
   }
 
   public final class WifiMigration {
@@ -7812,9 +7816,6 @@
     method public int getMaxNumberTxSpatialStreams();
     method public boolean isChannelWidthSupported(int);
     method public boolean isWifiStandardSupported(int);
-    method public void setChannelWidthSupported(int, boolean);
-    method public void setMaxNumberRxSpatialStreams(int);
-    method public void setMaxNumberTxSpatialStreams(int);
     method public void setWifiStandardSupport(int, boolean);
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.nl80211.DeviceWiphyCapabilities> CREATOR;
@@ -7985,7 +7986,7 @@
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
-    method @RequiresPermission(allOf={android.Manifest.permission.CONNECTIVITY_INTERNAL, android.Manifest.permission.CONFIGURE_WIFI_DISPLAY}) public void setMiracastMode(int);
+    method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int);
     method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
     method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
@@ -8944,7 +8945,7 @@
   }
 
   public final class PermissionManager {
-    method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+    method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -8952,7 +8953,7 @@
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
-    method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
     method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
   }
@@ -9435,7 +9436,6 @@
 
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
-    field @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask";
     field public static final int CARRIER_EDITED = 4; // 0x4
     field @NonNull public static final android.net.Uri DPC_URI;
     field public static final String EDITED_STATUS = "edited";
@@ -9444,11 +9444,6 @@
     field public static final String MODEM_PERSIST = "modem_cognitive";
     field public static final String MTU = "mtu";
     field public static final int NO_APN_SET_ID = 0; // 0x0
-    field public static final String PROFILE_ID = "profile_id";
-    field public static final String SKIP_464XLAT = "skip_464xlat";
-    field public static final int SKIP_464XLAT_DEFAULT = -1; // 0xffffffff
-    field public static final int SKIP_464XLAT_DISABLE = 0; // 0x0
-    field public static final int SKIP_464XLAT_ENABLE = 1; // 0x1
     field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
     field public static final int UNEDITED = 0; // 0x0
     field public static final int USER_DELETED = 2; // 0x2
@@ -9863,10 +9858,10 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method @NonNull public android.service.autofill.augmented.FillResponse build();
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
   }
 
   public final class FillWindow implements java.lang.AutoCloseable {
@@ -10912,19 +10907,6 @@
     method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
   }
 
-  public final class CdmaEriInformation implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getEriIconIndex();
-    method public int getEriIconMode();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CdmaEriInformation> CREATOR;
-    field public static final int ERI_FLASH = 2; // 0x2
-    field public static final int ERI_ICON_MODE_FLASH = 1; // 0x1
-    field public static final int ERI_ICON_MODE_NORMAL = 0; // 0x0
-    field public static final int ERI_OFF = 1; // 0x1
-    field public static final int ERI_ON = 0; // 0x0
-  }
-
   public class CellBroadcastIntents {
     method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
     field public static final String ACTION_AREA_INFO_UPDATED = "android.telephony.action.AREA_INFO_UPDATED";
@@ -10982,7 +10964,6 @@
   public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
-    method public boolean isUsingCarrierAggregation();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
   }
@@ -11220,19 +11201,6 @@
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
   }
 
-  public final class PinResult implements android.os.Parcelable {
-    ctor public PinResult(int, int);
-    method public int describeContents();
-    method public int getAttemptsRemaining();
-    method @NonNull public static android.telephony.PinResult getDefaultFailedResult();
-    method public int getType();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PinResult> CREATOR;
-    field public static final int PIN_RESULT_TYPE_FAILURE = 2; // 0x2
-    field public static final int PIN_RESULT_TYPE_INCORRECT = 1; // 0x1
-    field public static final int PIN_RESULT_TYPE_SUCCESS = 0; // 0x0
-  }
-
   public final class PreciseCallState implements android.os.Parcelable {
     ctor public PreciseCallState(int, int, int, int, int);
     method public int describeContents();
@@ -11364,11 +11332,9 @@
     method public void fillInNotifierBundle(@NonNull android.os.Bundle);
     method public int getDataNetworkType();
     method public int getDataRegistrationState();
-    method public boolean getDataRoamingFromRegistration();
     method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
-    method public int getNrFrequencyRange();
     method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle);
     field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
     field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
@@ -11620,7 +11586,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CdmaEriInformation getCdmaEriInformation();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
@@ -11697,6 +11662,7 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetAllCarrierActions();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void resetCarrierKeysForImsiEncryption();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void resetIms(int);
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void resetOtaEmergencyNumberDbFilePath();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean resetRadioConfig();
     method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings();
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -11727,15 +11693,13 @@
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
-    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPinReportPinResult(@NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
-    method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPukReportPinResult(@NonNull String, @NonNull String);
     method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
+    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
     method public void updateServiceLocation();
-    method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
     field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED";
     field public static final String ACTION_CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE = "com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE";
     field public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE = "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
@@ -11903,23 +11867,6 @@
 
 package android.telephony.data {
 
-  public class ApnSetting implements android.os.Parcelable {
-    method @NonNull public static String getApnTypesStringFromBitmask(int);
-    field public static final String TYPE_ALL_STRING = "*";
-    field public static final String TYPE_CBS_STRING = "cbs";
-    field public static final String TYPE_DEFAULT_STRING = "default";
-    field public static final String TYPE_DUN_STRING = "dun";
-    field public static final String TYPE_EMERGENCY_STRING = "emergency";
-    field public static final String TYPE_FOTA_STRING = "fota";
-    field public static final String TYPE_HIPRI_STRING = "hipri";
-    field public static final String TYPE_IA_STRING = "ia";
-    field public static final String TYPE_IMS_STRING = "ims";
-    field public static final String TYPE_MCX_STRING = "mcx";
-    field public static final String TYPE_MMS_STRING = "mms";
-    field public static final String TYPE_SUPL_STRING = "supl";
-    field public static final String TYPE_XCAP_STRING = "xcap";
-  }
-
   public final class DataCallResponse implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -12245,7 +12192,7 @@
     method public int getEmergencyServiceCategories();
     method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
-    method @Nullable public android.os.Bundle getProprietaryCallExtras();
+    method @NonNull public android.os.Bundle getProprietaryCallExtras();
     method public int getRestrictCause();
     method public int getServiceType();
     method public static int getVideoStateFromCallType(int);
@@ -12703,8 +12650,8 @@
     field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11
     field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17
     field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16
+    field public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16; // 0x10
     field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
-    field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
     field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
     field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
     field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 07b8969..23e2499 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -11,6 +11,12 @@
 
   public class AppOpsManager {
     method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
+    method @Deprecated public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+  }
+
+  @Deprecated public abstract static class AppOpsManager.AppOpsCollector extends android.app.AppOpsManager.OnOpNotedCallback {
+    ctor public AppOpsManager.AppOpsCollector();
+    method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
   }
 
   public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index d03539c..218b934 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -21,6 +21,7 @@
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
     field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
+    field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
     field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
     field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -590,6 +591,14 @@
 
 }
 
+package android.app.blob {
+
+  public class BlobStoreManager {
+    method public void waitForIdle(long) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+  }
+
+}
+
 package android.app.prediction {
 
   public final class AppPredictionContext implements android.os.Parcelable {
@@ -784,6 +793,8 @@
   }
 
   public abstract class ContentResolver {
+    method @NonNull public static android.net.Uri decodeFromFile(@NonNull java.io.File);
+    method @NonNull public static java.io.File encodeToFile(@NonNull android.net.Uri);
     method public static String[] getSyncAdapterPackagesForAuthorityAsUser(String, int);
   }
 
@@ -1268,7 +1279,7 @@
 
   public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
-    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+    method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
   }
 
   public final class LightsRequest {
@@ -1727,7 +1738,7 @@
   }
 
   public class EthernetManager {
-    method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+    method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
   }
 
   public static interface EthernetManager.TetheredInterfaceCallback {
@@ -1909,6 +1920,9 @@
     field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
     field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
     field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
+    field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
+    field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
+    field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
   }
 
   public static interface TetheringManager.OnTetheringEntitlementResultListener {
@@ -1925,6 +1939,7 @@
     ctor public TetheringManager.TetheringEventCallback();
     method public void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
     method public void onError(@NonNull String, int);
+    method public void onOffloadStatusChanged(int);
     method @Deprecated public void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
     method public void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
     method public void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
@@ -2797,9 +2812,9 @@
   }
 
   public final class PermissionManager {
-    method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+    method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
     method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
-    method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+    method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
   }
 
   public static final class PermissionManager.SplitPermissionInfo {
@@ -2915,6 +2930,11 @@
     method @NonNull public android.provider.DeviceConfig.Properties.Builder setString(@NonNull String, @Nullable String);
   }
 
+  public final class DocumentsContract {
+    method public static boolean isManageMode(@NonNull android.net.Uri);
+    method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
+  }
+
   public final class MediaStore {
     method @NonNull @WorkerThread public static android.net.Uri scanFile(@NonNull android.content.ContentResolver, @NonNull java.io.File);
     method @WorkerThread public static void scanVolume(@NonNull android.content.ContentResolver, @NonNull String);
@@ -3223,10 +3243,10 @@
   public static final class FillResponse.Builder {
     ctor public FillResponse.Builder();
     method @NonNull public android.service.autofill.augmented.FillResponse build();
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@Nullable java.util.List<android.service.autofill.InlinePresentation>);
-    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@NonNull android.os.Bundle);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@NonNull android.service.autofill.augmented.FillWindow);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineActions(@NonNull java.util.List<android.service.autofill.InlineAction>);
+    method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@NonNull java.util.List<android.service.autofill.Dataset>);
   }
 
   public final class FillWindow implements java.lang.AutoCloseable {
@@ -3728,11 +3748,12 @@
     method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
+    method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void resetOtaEmergencyNumberDbFilePath();
     method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
     method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSystemSelectionChannels(@NonNull java.util.List<android.telephony.RadioAccessSpecifier>);
-    method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String);
+    method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateOtaEmergencyNumberDbFilePath(@NonNull android.os.ParcelFileDescriptor);
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
     field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
     field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -3833,7 +3854,7 @@
     method public int getEmergencyServiceCategories();
     method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
     method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
-    method @Nullable public android.os.Bundle getProprietaryCallExtras();
+    method @NonNull public android.os.Bundle getProprietaryCallExtras();
     method public int getRestrictCause();
     method public int getServiceType();
     method public static int getVideoStateFromCallType(int);
@@ -4288,8 +4309,8 @@
     field public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17; // 0x11
     field public static final int KEY_RCS_CAPABILITY_POLL_LIST_SUB_EXP_SEC = 23; // 0x17
     field public static final int KEY_RCS_MAX_NUM_ENTRIES_IN_RCL = 22; // 0x16
+    field public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16; // 0x10
     field public static final int KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS = 21; // 0x15
-    field public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16; // 0x10
     field public static final int KEY_RCS_PUBLISH_TIMER_SEC = 15; // 0xf
     field public static final int KEY_REGISTRATION_DOMAIN_NAME = 12; // 0xc
     field public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33; // 0x21
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index bd6ca47..33bfe51 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -113,8 +113,8 @@
         "libbase",
         "libcutils",
         "libprotoutil",
-        "libstatslog",
         "libstatsmetadata",
+        "libstatslog_statsd",
         "libsysutils",
         "libutils",
     ],
@@ -171,6 +171,37 @@
     ],
 }
 
+genrule {
+    name: "statslog_statsd.h",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_statsd.h --module statsd --namespace android,os,statsd,util",
+    out: [
+        "statslog_statsd.h",
+    ],
+}
+
+genrule {
+    name: "statslog_statsd.cpp",
+    tools: ["stats-log-api-gen"],
+    cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_statsd.cpp --module statsd --namespace android,os,statsd,util --importHeader statslog_statsd.h",
+    out: [
+        "statslog_statsd.cpp",
+    ],
+}
+
+cc_library_static {
+    name: "libstatslog_statsd",
+    generated_sources: ["statslog_statsd.cpp"],
+    generated_headers: ["statslog_statsd.h"],
+    export_generated_headers: ["statslog_statsd.h"],
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+    ],
+    shared_libs: [
+        "libstatssocket",
+    ]
+}
 
 // =========
 // statsd
@@ -300,6 +331,7 @@
     static_libs: [
         "libgmock",
         "libplatformprotos",
+        "libstatslog", //TODO(b/150976524): remove this when the tests no longer hardcode atoms.
         "libstatssocket_private",
     ],
 
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 649c004..69b9fc7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -34,7 +34,7 @@
 #include "state/StateManager.h"
 #include "stats_log_util.h"
 #include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 #include "storage/StorageManager.h"
 
 using namespace android;
@@ -287,17 +287,17 @@
         int64_t firstId = trainInfo->experimentIds.at(0);
         auto& ids = trainInfo->experimentIds;
         switch (trainInfo->status) {
-            case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
+            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
                 if (find(ids.begin(), ids.end(), firstId + 1) == ids.end()) {
                     ids.push_back(firstId + 1);
                 }
                 break;
-            case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
+            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
                 if (find(ids.begin(), ids.end(), firstId + 2) == ids.end()) {
                     ids.push_back(firstId + 2);
                 }
                 break;
-            case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
+            case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
                 if (find(ids.begin(), ids.end(), firstId + 3) == ids.end()) {
                     ids.push_back(firstId + 3);
                 }
@@ -366,13 +366,13 @@
     int64_t firstId = trainInfoOnDisk.experimentIds[0];
     auto& ids = trainInfoOnDisk.experimentIds;
     switch (rollbackTypeIn) {
-        case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+      case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
             if (find(ids.begin(), ids.end(), firstId + 4) == ids.end()) {
                 ids.push_back(firstId + 4);
             }
             StorageManager::writeTrainInfo(trainInfoOnDisk);
             break;
-        case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+      case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
             if (find(ids.begin(), ids.end(), firstId + 5) == ids.end()) {
                 ids.push_back(firstId + 5);
             }
@@ -405,13 +405,13 @@
 
     // Hard-coded logic to update train info on disk and fill in any information
     // this log event may be missing.
-    if (event->GetTagId() == android::util::BINARY_PUSH_STATE_CHANGED) {
+    if (event->GetTagId() == android::os::statsd::util::BINARY_PUSH_STATE_CHANGED) {
         onBinaryPushStateChangedEventLocked(event);
     }
 
     // Hard-coded logic to update experiment ids on disk for certain rollback
     // types and fill the rollback atom with experiment ids
-    if (event->GetTagId() == android::util::WATCHDOG_ROLLBACK_OCCURRED) {
+    if (event->GetTagId() == android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED) {
         onWatchdogRollbackOccurredLocked(event);
     }
 
@@ -429,7 +429,7 @@
 
     // Hard-coded logic to update the isolated uid's in the uid-map.
     // The field numbers need to be currently updated by hand with atoms.proto
-    if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+    if (event->GetTagId() == android::os::statsd::util::ISOLATED_UID_CHANGED) {
         onIsolatedUidChangedEventLocked(*event);
     }
 
@@ -446,7 +446,7 @@
     }
 
 
-    if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
+    if (event->GetTagId() != android::os::statsd::util::ISOLATED_UID_CHANGED) {
         // Map the isolated uid to host uid if necessary.
         mapIsolatedUidToHostUidIfNecessaryLocked(event);
     }
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index f18aaa5..07579bb 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -32,7 +32,7 @@
 #include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
 #include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
 #include <private/android_filesystem_config.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/system_properties.h>
@@ -767,7 +767,8 @@
     }
     if (good) {
         dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
-        android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
+        android::os::statsd::util::stats_write(
+                android::os::statsd::util::APP_BREADCRUMB_REPORTED, uid, label, state);
     } else {
         print_cmd_help(out);
         return UNKNOWN_ERROR;
@@ -930,8 +931,6 @@
     ENFORCE_UID(AID_SYSTEM);
 
     VLOG("StatsService::informOnePackage was called");
-    // TODO(b/149254662): This is gross. We should consider changing statsd
-    // internals to use std::string.
     String16 utf16App = String16(app.c_str());
     String16 utf16VersionString = String16(versionString.c_str());
     String16 utf16Installer = String16(installer.c_str());
@@ -1190,7 +1189,7 @@
 Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
     // Permission check not necessary as it's meant for applications to write to
     // statsd.
-    android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
+    android::os::statsd::util::stats_write(android::os::statsd::util::APP_BREADCRUMB_REPORTED,
                                (int32_t) AIBinder_getCallingUid(), label,
                                state);
     return Status::ok();
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
index 02291181..b632d04 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp
@@ -38,8 +38,6 @@
 void AlarmMonitor::setStatsCompanionService(
         shared_ptr<IStatsCompanionService> statsCompanionService) {
     std::lock_guard<std::mutex> lock(mLock);
-    // TODO(b/149254662): determine if tmpForLock is needed now that we have moved
-    // from sp to shared_ptr
     shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
     mStatsCompanionService = statsCompanionService;
     if (statsCompanionService == nullptr) {
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 019a9f7..5722f92 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -23,7 +23,6 @@
 #include "stats_util.h"
 #include "storage/StorageManager.h"
 
-#include <statslog.h>
 #include <time.h>
 
 namespace android {
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7ace44e..a21abbf 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -25,7 +25,7 @@
 #include "subscriber/SubscriberReporter.h"
 
 #include <inttypes.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
 #include <time.h>
 
 namespace android {
@@ -235,8 +235,8 @@
     StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
 
     // TODO(b/110564268): This should also take in the const MetricDimensionKey& key?
-    android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
-                               mConfigKey.GetId(), mAlert.id());
+    util::stats_write(util::ANOMALY_DETECTED, mConfigKey.GetUid(),
+                      mConfigKey.GetId(), mAlert.id());
 }
 
 void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9645a46..32a5243 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -122,10 +122,10 @@
         SettingChanged setting_changed = 41 [(module) = "framework"];
         ActivityForegroundStateChanged activity_foreground_state_changed =
                 42 [(module) = "framework"];
-        IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework"];
+        IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework", (module) = "statsd"];
         PacketWakeupOccurred packet_wakeup_occurred = 44 [(module) = "framework"];
         WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
-        AnomalyDetected anomaly_detected = 46;
+        AnomalyDetected anomaly_detected = 46 [(module) = "statsd"];
         AppBreadcrumbReported app_breadcrumb_reported =
                 47 [(allow_from_any_uid) = true, (module) = "statsd"];
         AppStartOccurred app_start_occurred = 48 [(module) = "framework"];
@@ -138,7 +138,7 @@
         AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
         ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
         BootSequenceReported boot_sequence_reported = 57;
-        DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
+        DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true, (module) = "statsd"];
         OverlayStateChanged overlay_state_changed = 59 [(module) = "framework"];
         ForegroundServiceStateChanged foreground_service_state_changed
                 = 60 [(module) = "framework"];
@@ -166,7 +166,7 @@
         LowMemReported low_mem_reported = 81 [(module) = "framework"];
         GenericAtom generic_atom = 82;
         KeyValuePairsAtom key_value_pairs_atom =
-                83 [(allow_from_any_uid) = true, (module) = "framework"];
+                83 [(allow_from_any_uid) = true, (module) = "framework", (module) = "statsd"];
         VibratorStateChanged vibrator_state_changed = 84 [(module) = "framework"];
         DeferredJobStatsReported deferred_job_stats_reported = 85 [(module) = "framework"];
         ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true];
@@ -242,7 +242,8 @@
         AdbConnectionChanged adb_connection_changed = 144 [(module) = "framework"];
         SpeechDspStatReported speech_dsp_stat_reported = 145;
         UsbContaminantReported usb_contaminant_reported = 146 [(module) = "framework"];
-        WatchdogRollbackOccurred watchdog_rollback_occurred = 147 [(module) = "framework"];
+        WatchdogRollbackOccurred watchdog_rollback_occurred =
+                147 [(module) = "framework", (module) = "statsd"];
         BiometricSystemHealthIssueDetected biometric_system_health_issue_detected =
                 148 [(module) = "framework"];
         BubbleUIChanged bubble_ui_changed = 149 [(module) = "sysui"];
@@ -412,7 +413,8 @@
         SubsystemSleepState subsystem_sleep_state = 10005;
         CpuTimePerFreq cpu_time_per_freq = 10008 [(module) = "framework"];
         CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework"];
-        CpuTimePerUidFreq cpu_time_per_uid_freq = 10010 [(module) = "framework"];
+        CpuTimePerUidFreq cpu_time_per_uid_freq =
+                10010 [(module) = "framework", (module) = "statsd"];
         WifiActivityInfo wifi_activity_info = 10011 [(module) = "framework"];
         ModemActivityInfo modem_activity_info = 10012 [(module) = "framework"];
         BluetoothActivityInfo bluetooth_activity_info = 10007 [(module) = "framework"];
@@ -425,9 +427,9 @@
         RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
         FullBatteryCapacity full_battery_capacity = 10020 [(module) = "framework"];
         Temperature temperature = 10021 [(module) = "framework"];
-        BinderCalls binder_calls = 10022 [(module) = "framework"];
+        BinderCalls binder_calls = 10022 [(module) = "framework", (module) = "statsd"];
         BinderCallsExceptions binder_calls_exceptions = 10023 [(module) = "framework"];
-        LooperStats looper_stats = 10024 [(module) = "framework"];
+        LooperStats looper_stats = 10024 [(module) = "framework", (module) = "statsd"];
         DiskStats disk_stats = 10025 [(module) = "framework"];
         DirectoryUsage directory_usage = 10026 [(module) = "framework"];
         AppSize app_size = 10027 [(module) = "framework"];
@@ -455,7 +457,7 @@
         NumFacesEnrolled num_faces_enrolled = 10048 [(module) = "framework"];
         RoleHolder role_holder = 10049 [(module) = "framework"];
         DangerousPermissionState dangerous_permission_state = 10050 [(module) = "framework"];
-        TrainInfo train_info = 10051;
+        TrainInfo train_info = 10051 [(module) = "statsd"];
         TimeZoneDataInfo time_zone_data_info = 10052 [(module) = "framework"];
         ExternalStorageInfo external_storage_info = 10053 [(module) = "framework"];
         GpuStatsGlobalInfo gpu_stats_global_info = 10054;
@@ -7640,6 +7642,9 @@
 
     // Whether AppOps is guarded by Runtime permission
     optional bool is_runtime_permission = 11;
+
+    // Sampling rate used on device, from 0 to 100
+    optional int32 sampling_rate = 12;
 }
 
 /**
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 9bdb588..6d9c644 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -54,20 +54,22 @@
     shared_ptr<IPendingIntentRef> mPir;
 };
 
-static void configReceiverDied(void* cookie) {
+void ConfigManager::configReceiverDied(void* cookie) {
     auto cookie_ = static_cast<ConfigReceiverDeathCookie*>(cookie);
-    sp<ConfigManager> configManager = cookie_->mConfigManager;
-    ConfigKey configKey = cookie_->mConfigKey;
-    shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+    sp<ConfigManager>& thiz = cookie_->mConfigManager;
+    ConfigKey& configKey = cookie_->mConfigKey;
+    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
 
-    // TODO(b/149254662): Fix threading. This currently fails if a new
-    // pir gets set between the get and the remove.
-    if (configManager->GetConfigReceiver(configKey) == pir) {
-        configManager->RemoveConfigReceiver(configKey);
+    // Erase the mapping from the config key to the config receiver (pir) if the
+    // mapping still exists.
+    lock_guard<mutex> lock(thiz->mMutex);
+    auto it = thiz->mConfigReceivers.find(configKey);
+    if (it != thiz->mConfigReceivers.end() && it->second == pir) {
+        thiz->mConfigReceivers.erase(configKey);
     }
-    // The death recipient corresponding to this specific pir can never
-    // be triggered again, so free up resources.
-    // TODO(b/149254662): Investigate other options to manage the memory.
+
+    // The death recipient corresponding to this specific pir can never be
+    // triggered again, so free up resources.
     delete cookie_;
 }
 
@@ -83,26 +85,29 @@
     shared_ptr<IPendingIntentRef> mPir;
 };
 
-static void activeConfigChangedReceiverDied(void* cookie) {
+void ConfigManager::activeConfigChangedReceiverDied(void* cookie) {
     auto cookie_ = static_cast<ActiveConfigChangedReceiverDeathCookie*>(cookie);
-    sp<ConfigManager> configManager = cookie_->mConfigManager;
+    sp<ConfigManager>& thiz = cookie_->mConfigManager;
     int uid = cookie_->mUid;
-    shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
 
-    // TODO(b/149254662): Fix threading. This currently fails if a new
-    // pir gets set between the get and the remove.
-    if (configManager->GetActiveConfigsChangedReceiver(uid) == pir) {
-        configManager->RemoveActiveConfigsChangedReceiver(uid);
+    // Erase the mapping from the config key to the active config changed
+    // receiver (pir) if the mapping still exists.
+    lock_guard<mutex> lock(thiz->mMutex);
+    auto it = thiz->mActiveConfigsChangedReceivers.find(uid);
+    if (it != thiz->mActiveConfigsChangedReceivers.end() && it->second == pir) {
+        thiz->mActiveConfigsChangedReceivers.erase(uid);
     }
+
     // The death recipient corresponding to this specific pir can never
     // be triggered again, so free up resources.
     delete cookie_;
 }
 
-ConfigManager::ConfigManager():
+ConfigManager::ConfigManager() :
     mConfigReceiverDeathRecipient(AIBinder_DeathRecipient_new(configReceiverDied)),
     mActiveConfigChangedReceiverDeathRecipient(
-        AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
+            AIBinder_DeathRecipient_new(activeConfigChangedReceiverDied)) {
 }
 
 ConfigManager::~ConfigManager() {
@@ -189,8 +194,10 @@
 
 void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
                                                     const shared_ptr<IPendingIntentRef>& pir) {
-    lock_guard<mutex> lock(mMutex);
-    mActiveConfigsChangedReceivers[uid] = pir;
+    {
+        lock_guard<mutex> lock(mMutex);
+        mActiveConfigsChangedReceivers[uid] = pir;
+    }
     AIBinder_linkToDeath(pir->asBinder().get(), mActiveConfigChangedReceiverDeathRecipient.get(),
                          new ActiveConfigChangedReceiverDeathCookie(this, uid, pir));
 }
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 824e588..40146b1 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -161,6 +161,19 @@
     // IPendingIntentRef dies.
     ::ndk::ScopedAIBinder_DeathRecipient mConfigReceiverDeathRecipient;
     ::ndk::ScopedAIBinder_DeathRecipient mActiveConfigChangedReceiverDeathRecipient;
+
+    /**
+     * Death recipient callback that is called when a config receiver dies.
+     * The cookie is a pointer to a ConfigReceiverDeathCookie.
+     */
+    static void configReceiverDied(void* cookie);
+
+    /**
+     * Death recipient callback that is called when an active config changed
+     * receiver dies. The cookie is a pointer to an
+     * ActiveConfigChangedReceiverDeathCookie.
+     */
+    static void activeConfigChangedReceiverDied(void* cookie);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 1c38542..8b6a5a1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -32,7 +32,7 @@
 #include "../statscompanion_util.h"
 #include "StatsCallbackPuller.h"
 #include "TrainInfoPuller.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 
 using std::shared_ptr;
 using std::vector;
@@ -47,7 +47,7 @@
 StatsPullerManager::StatsPullerManager()
     : kAllPullAtomInfo({
               // TrainInfo.
-              {{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()},
+              {{.atomTag = util::TRAIN_INFO}, new TrainInfoPuller()},
       }),
       mNextPullTimeNs(NO_ALARM_UPDATE) {
 }
@@ -85,12 +85,9 @@
         return;
     }
 
-    // TODO(b/149254662): Why are we creating a copy here? This is different
-    // from the other places where we create a copy because we don't reassign
-    // mStatsCompanionService so a destructor can't implicitly be called...
-    shared_ptr<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
-    if (statsCompanionServiceCopy != nullptr) {
-        statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000);
+    // TODO(b/151045771): do not hold a lock while making a binder call
+    if (mStatsCompanionService != nullptr) {
+        mStatsCompanionService->setPullingAlarm(mNextPullTimeNs / 1000000);
     } else {
         VLOG("StatsCompanionService not available. Alarm not set.");
     }
@@ -99,8 +96,6 @@
 
 void StatsPullerManager::SetStatsCompanionService(
         shared_ptr<IStatsCompanionService> statsCompanionService) {
-    // TODO(b/149254662): Why are we using AutoMutex instead of lock_guard?
-    // Additionally, do we need the temporary shared_ptr to prevent deadlocks?
     AutoMutex _l(mLock);
     shared_ptr<IStatsCompanionService> tmpForLock = mStatsCompanionService;
     mStatsCompanionService = statsCompanionService;
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
index a7d8d4e..3837f4a 100644
--- a/cmds/statsd/src/external/TrainInfoPuller.cpp
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -22,7 +22,7 @@
 #include "TrainInfoPuller.h"
 #include "logd/LogEvent.h"
 #include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 #include "storage/StorageManager.h"
 
 using std::make_shared;
@@ -33,7 +33,7 @@
 namespace statsd {
 
 TrainInfoPuller::TrainInfoPuller() :
-    StatsPuller(android::util::TRAIN_INFO) {
+    StatsPuller(util::TRAIN_INFO) {
 }
 
 bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 3054b6d..2bd13d7 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -20,7 +20,7 @@
 
 #include <android/util/ProtoOutputStream.h>
 #include "../stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 #include "storage/StorageManager.h"
 
 namespace android {
@@ -113,9 +113,9 @@
 const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_TIME = 2;
 
 const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
-        {android::util::BINDER_CALLS, {6000, 10000}},
-        {android::util::LOOPER_STATS, {1500, 2500}},
-        {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
+        {util::BINDER_CALLS, {6000, 10000}},
+        {util::LOOPER_STATS, {1500, 2500}},
+        {util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
 };
 
 StatsdStats::StatsdStats() {
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 974e203..258f84d 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -18,7 +18,7 @@
 #include "logd/LogEvent.h"
 
 #include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 
 #include <android/binder_ibinder.h>
 #include <android-base/stringprintf.h>
@@ -100,7 +100,7 @@
                    const std::map<int32_t, float>& float_map) {
     mLogdTimestampNs = wallClockTimestampNs;
     mElapsedTimestampNs = elapsedTimestampNs;
-    mTagId = android::util::KEY_VALUE_PAIRS_ATOM;
+    mTagId = util::KEY_VALUE_PAIRS_ATOM;
     mLogUid = uid;
 
     int pos[] = {1, 1, 1};
@@ -153,7 +153,7 @@
                    const std::vector<uint8_t>& experimentIds, int32_t userId) {
     mLogdTimestampNs = getWallClockNs();
     mElapsedTimestampNs = getElapsedRealtimeNs();
-    mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
+    mTagId = util::BINARY_PUSH_STATE_CHANGED;
     mLogUid = AIBinder_getCallingUid();
     mLogPid = AIBinder_getCallingPid();
 
@@ -172,7 +172,7 @@
                    const InstallTrainInfo& trainInfo) {
     mLogdTimestampNs = wallClockTimestampNs;
     mElapsedTimestampNs = elapsedTimestampNs;
-    mTagId = android::util::TRAIN_INFO;
+    mTagId = util::TRAIN_INFO;
 
     mValues.push_back(
             FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 3940aa8..b68eeb8 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -328,4 +328,3 @@
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
-
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 536700f..6f54ea7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -31,7 +31,7 @@
 #include "state/StateManager.h"
 #include "stats_log_util.h"
 #include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
 
 using android::util::FIELD_COUNT_REPEATED;
 using android::util::FIELD_TYPE_INT32;
@@ -291,7 +291,7 @@
 }
 
 bool MetricsManager::eventSanityCheck(const LogEvent& event) {
-    if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
+    if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
         // Check that app breadcrumb reported fields are valid.
         status_t err = NO_ERROR;
 
@@ -318,7 +318,7 @@
             VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
             return false;
         }
-    } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
+    } else if (event.GetTagId() == util::DAVEY_OCCURRED) {
         // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
         // Check that the davey duration is reasonable. Max length check is for privacy.
         status_t err = NO_ERROR;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 4e3c506..02fe7b1 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -139,7 +139,7 @@
     // record is deleted.
     void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
                       bool includeVersionStrings, bool includeInstaller,
-                      util::ProtoOutputStream* proto);
+                      ProtoOutputStream* proto);
 
     // Forces the output to be cleared. We still generate a snapshot based on the current state.
     // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index 93af5e9..c915ef3 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -39,33 +39,47 @@
     shared_ptr<IPendingIntentRef> mPir;
 };
 
-static void broadcastSubscriberDied(void* cookie) {
-    BroadcastSubscriberDeathCookie* cookie_ = (BroadcastSubscriberDeathCookie*)cookie;
-    ConfigKey configKey = cookie_->mConfigKey;
+void SubscriberReporter::broadcastSubscriberDied(void* cookie) {
+    auto cookie_ = static_cast<BroadcastSubscriberDeathCookie*>(cookie);
+    ConfigKey& configKey = cookie_->mConfigKey;
     int64_t subscriberId = cookie_->mSubscriberId;
-    shared_ptr<IPendingIntentRef> pir = cookie_->mPir;
+    shared_ptr<IPendingIntentRef>& pir = cookie_->mPir;
 
-    // TODO(b/149254662): Fix threading. This currently fails if a new pir gets
-    // set between the get and the unset.
-    if (SubscriberReporter::getInstance().getBroadcastSubscriber(configKey, subscriberId) == pir) {
-        SubscriberReporter::getInstance().unsetBroadcastSubscriber(configKey, subscriberId);
+    SubscriberReporter& thiz = getInstance();
+
+    // Erase the mapping from a (config_key, subscriberId) to a pir if the
+    // mapping exists.
+    lock_guard<mutex> lock(thiz.mLock);
+    auto subscriberMapIt = thiz.mIntentMap.find(configKey);
+    if (subscriberMapIt != thiz.mIntentMap.end()) {
+        auto subscriberMap = subscriberMapIt->second;
+        auto pirIt = subscriberMap.find(subscriberId);
+        if (pirIt != subscriberMap.end() && pirIt->second == pir) {
+            subscriberMap.erase(subscriberId);
+            if (subscriberMap.empty()) {
+                thiz.mIntentMap.erase(configKey);
+            }
+        }
     }
+
     // The death recipient corresponding to this specific pir can never be
     // triggered again, so free up resources.
     delete cookie_;
 }
 
-static ::ndk::ScopedAIBinder_DeathRecipient sBroadcastSubscriberDeathRecipient(
-        AIBinder_DeathRecipient_new(broadcastSubscriberDied));
+SubscriberReporter::SubscriberReporter() :
+    mBroadcastSubscriberDeathRecipient(AIBinder_DeathRecipient_new(broadcastSubscriberDied)) {
+}
 
 void SubscriberReporter::setBroadcastSubscriber(const ConfigKey& configKey,
                                                 int64_t subscriberId,
                                                 const shared_ptr<IPendingIntentRef>& pir) {
     VLOG("SubscriberReporter::setBroadcastSubscriber called.");
-    lock_guard<mutex> lock(mLock);
-    mIntentMap[configKey][subscriberId] = pir;
-    // TODO(b/149254662): Is it ok to call linkToDeath while holding a lock?
-    AIBinder_linkToDeath(pir->asBinder().get(), sBroadcastSubscriberDeathRecipient.get(),
+    {
+        lock_guard<mutex> lock(mLock);
+        mIntentMap[configKey][subscriberId] = pir;
+    }
+    AIBinder_linkToDeath(pir->asBinder().get(), mBroadcastSubscriberDeathRecipient.get(),
                          new BroadcastSubscriberDeathCookie(configKey, subscriberId, pir));
 }
 
@@ -103,8 +117,6 @@
     }
     int64_t subscriberId = subscription.broadcast_subscriber_details().subscriber_id();
 
-    // TODO(b/149254662): Is there a way to convert a RepeatedPtrField into a
-    // vector without copying?
     vector<string> cookies;
     cookies.reserve(subscription.broadcast_subscriber_details().cookie_size());
     for (auto& cookie : subscription.broadcast_subscriber_details().cookie()) {
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.h b/cmds/statsd/src/subscriber/SubscriberReporter.h
index 0f97d39..4fe4281 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.h
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.h
@@ -78,7 +78,7 @@
                                                          int64_t subscriberId);
 
 private:
-    SubscriberReporter() {};
+    SubscriberReporter();
 
     mutable mutex mLock;
 
@@ -94,6 +94,14 @@
                              const Subscription& subscription,
                              const vector<string>& cookies,
                              const MetricDimensionKey& dimKey) const;
+
+    ::ndk::ScopedAIBinder_DeathRecipient mBroadcastSubscriberDeathRecipient;
+
+    /**
+     * Death recipient callback that is called when a broadcast subscriber dies.
+     * The cookie is a pointer to a BroadcastSubscriberDeathCookie.
+     */
+    static void broadcastSubscriberDied(void* cookie);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 4b78e30..7febb35 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -137,7 +137,9 @@
                                             simplePredicate, trackerNameIndexMap);
     EXPECT_FALSE(conditionTracker.isSliced());
 
-    LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+    // This event is not accessed in this test besides dimensions which is why this is okay.
+    // This is technically an invalid LogEvent because we do not call parseBuffer.
+    LogEvent event(/*uid=*/0, /*pid=*/0);
 
     vector<MatchingState> matcherState;
     matcherState.push_back(MatchingState::kNotMatched);
@@ -222,7 +224,9 @@
                                             trackerNameIndexMap);
     EXPECT_FALSE(conditionTracker.isSliced());
 
-    LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+    // This event is not accessed in this test besides dimensions which is why this is okay.
+    // This is technically an invalid LogEvent because we do not call parseBuffer.
+    LogEvent event(/*uid=*/0, /*pid=*/0);
 
     // one matched start
     vector<MatchingState> matcherState;
@@ -296,8 +300,8 @@
 
         std::vector<int> uids = {111, 222, 333};
 
-        LogEvent event(/*uid=*/-1, /*pid=*/-1);
-        makeWakeLockEvent(&event, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
+        LogEvent event1(/*uid=*/0, /*pid=*/0);
+        makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
 
         // one matched start
         vector<MatchingState> matcherState;
@@ -308,7 +312,7 @@
         vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
         vector<bool> changedCache(1, false);
 
-        conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
+        conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
                                            changedCache);
 
         if (position == Position::FIRST || position == Position::LAST) {
@@ -333,7 +337,7 @@
         EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
 
         // another wake lock acquired by this uid
-        LogEvent event2(/*uid=*/-1, /*pid=*/-1);
+        LogEvent event2(/*uid=*/0, /*pid=*/0);
         makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1);
         matcherState.clear();
         matcherState.push_back(MatchingState::kMatched);
@@ -353,7 +357,7 @@
 
 
         // wake lock 1 release
-        LogEvent event3(/*uid=*/-1, /*pid=*/-1);
+        LogEvent event3(/*uid=*/0, /*pid=*/0);
         makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
         matcherState.clear();
         matcherState.push_back(MatchingState::kNotMatched);
@@ -372,7 +376,7 @@
         EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
         EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
 
-        LogEvent event4(/*uid=*/-1, /*pid=*/-1);
+        LogEvent event4(/*uid=*/0, /*pid=*/0);
         makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
         matcherState.clear();
         matcherState.push_back(MatchingState::kNotMatched);
@@ -399,246 +403,235 @@
 
 }
 
-//TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
-//    std::vector<sp<ConditionTracker>> allConditions;
-//
-//    SimplePredicate simplePredicate = getWakeLockHeldCondition(
-//            true /*nesting*/, true /*default to false*/, false /*slice output by uid*/,
-//            Position::ANY /* position */);
-//    string conditionName = "WL_HELD";
-//
-//    unordered_map<int64_t, int> trackerNameIndexMap;
-//    trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-//    trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-//    trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-//    SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-//                                            0 /*condition tracker index*/, simplePredicate,
-//                                            trackerNameIndexMap);
-//
-//    EXPECT_FALSE(conditionTracker.isSliced());
-//
-//    std::vector<int> uid_list1 = {111, 1111, 11111};
-//    string uid1_wl1 = "wl1_1";
-//    std::vector<int> uid_list2 = {222, 2222, 22222};
-//    string uid2_wl1 = "wl2_1";
-//
-//    LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-//    makeWakeLockEvent(&event, uid_list1, uid1_wl1, 1);
-//
-//    // one matched start for uid1
-//    vector<MatchingState> matcherState;
-//    matcherState.push_back(MatchingState::kMatched);
-//    matcherState.push_back(MatchingState::kNotMatched);
-//    matcherState.push_back(MatchingState::kNotMatched);
-//    vector<sp<ConditionTracker>> allPredicates;
-//    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-//    vector<bool> changedCache(1, false);
-//
-//    conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-//                                       changedCache);
-//
-//    EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-//    EXPECT_TRUE(changedCache[0]);
-//
-//    // Now test query
-//    ConditionKey queryKey;
-//    conditionCache[0] = ConditionState::kNotEvaluated;
-//
-//    conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                    true,
-//                                    conditionCache);
-//    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-//    // another wake lock acquired by this uid
-//    LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-//    makeWakeLockEvent(&event2, uid_list2, uid2_wl1, 1);
-//    matcherState.clear();
-//    matcherState.push_back(MatchingState::kMatched);
-//    matcherState.push_back(MatchingState::kNotMatched);
-//    conditionCache[0] = ConditionState::kNotEvaluated;
-//    changedCache[0] = false;
-//    conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-//                                       changedCache);
-//    EXPECT_FALSE(changedCache[0]);
-//
-//    // uid1 wake lock 1 release
-//    LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
-//    makeWakeLockEvent(&event3, uid_list1, uid1_wl1, 0);  // now release it.
-//    matcherState.clear();
-//    matcherState.push_back(MatchingState::kNotMatched);
-//    matcherState.push_back(MatchingState::kMatched);
-//    conditionCache[0] = ConditionState::kNotEvaluated;
-//    changedCache[0] = false;
-//    conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-//                                       changedCache);
-//    // nothing changes, because uid2 is still holding wl.
-//    EXPECT_FALSE(changedCache[0]);
-//
-//    LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
-//    makeWakeLockEvent(&event4, uid_list2, uid2_wl1, 0);  // now release it.
-//    matcherState.clear();
-//    matcherState.push_back(MatchingState::kNotMatched);
-//    matcherState.push_back(MatchingState::kMatched);
-//    conditionCache[0] = ConditionState::kNotEvaluated;
-//    changedCache[0] = false;
-//    conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
-//                                       changedCache);
-//    EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-//    EXPECT_TRUE(changedCache[0]);
-//
-//    // query again
-//    conditionCache[0] = ConditionState::kNotEvaluated;
-//    conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                    true,
-//                                    conditionCache);
-//    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//}
-//
-//TEST(SimpleConditionTrackerTest, TestStopAll) {
-//    std::vector<sp<ConditionTracker>> allConditions;
-//    for (Position position :
-//            { Position::FIRST, Position::LAST }) {
-//        SimplePredicate simplePredicate = getWakeLockHeldCondition(
-//                true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
-//                position);
-//        string conditionName = "WL_HELD_BY_UID3";
-//
-//        unordered_map<int64_t, int> trackerNameIndexMap;
-//        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-//        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-//        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-//        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-//                                                0 /*condition tracker index*/, simplePredicate,
-//                                                trackerNameIndexMap);
-//
-//        std::vector<int> uid_list1 = {111, 1111, 11111};
-//        std::vector<int> uid_list2 = {222, 2222, 22222};
-//
-//        LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-//        makeWakeLockEvent(&event, uid_list1, "wl1", 1);
-//
-//        // one matched start
-//        vector<MatchingState> matcherState;
-//        matcherState.push_back(MatchingState::kMatched);
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        vector<sp<ConditionTracker>> allPredicates;
-//        vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-//        vector<bool> changedCache(1, false);
-//
-//        conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-//                                           changedCache);
-//        if (position == Position::FIRST ||
-//            position == Position::LAST) {
-//            EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-//        } else {
-//            EXPECT_EQ(uid_list1.size(), conditionTracker.mSlicedConditionState.size());
-//        }
-//        EXPECT_TRUE(changedCache[0]);
-//        {
-//            if (position == Position::FIRST ||
-//                position == Position::LAST) {
-//                EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-//            } else {
-//                EXPECT_EQ(uid_list1.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-//            }
-//        }
-//
-//        // Now test query
-//        const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//
-//        conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                        false,
-//                                        conditionCache);
-//        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-//        // another wake lock acquired by uid2
-//        LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-//        makeWakeLockEvent(&event2, uid_list2, "wl2", 1);
-//        matcherState.clear();
-//        matcherState.push_back(MatchingState::kMatched);
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//        changedCache[0] = false;
-//        conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-//                                           changedCache);
-//        if (position == Position::FIRST ||
-//            position == Position::LAST) {
-//            EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
-//        } else {
-//            EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-//                      conditionTracker.mSlicedConditionState.size());
-//        }
-//        EXPECT_TRUE(changedCache[0]);
-//        {
-//            if (position == Position::FIRST ||
-//                position == Position::LAST) {
-//                EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-//            } else {
-//                EXPECT_EQ(uid_list2.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-//            }
-//        }
-//
-//
-//        // TEST QUERY
-//        const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//        conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                        false,
-//                                        conditionCache);
-//
-//        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-//
-//        // stop all event
-//        LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
-//        matcherState.clear();
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        matcherState.push_back(MatchingState::kNotMatched);
-//        matcherState.push_back(MatchingState::kMatched);
-//
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//        changedCache[0] = false;
-//        conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-//                                           changedCache);
-//        EXPECT_TRUE(changedCache[0]);
-//        EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-//        {
-//            if (position == Position::FIRST || position == Position::LAST) {
-//                EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-//            } else {
-//                EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-//                          conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-//                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-//            }
-//        }
-//
-//        // TEST QUERY
-//        const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//        conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                        false,
-//                                        conditionCache);
-//        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//
-//        // TEST QUERY
-//        const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
-//        conditionCache[0] = ConditionState::kNotEvaluated;
-//        conditionTracker.isConditionMet(queryKey, allPredicates,
-//                                        false,
-//                                        conditionCache);
-//        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//    }
-//}
+TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
+    std::vector<sp<ConditionTracker>> allConditions;
+
+    SimplePredicate simplePredicate =
+            getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+                                     false /*slice output by uid*/, Position::ANY /* position */);
+    string conditionName = "WL_HELD";
+
+    unordered_map<int64_t, int> trackerNameIndexMap;
+    trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+    trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+    trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+    SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+                                            0 /*condition tracker index*/, simplePredicate,
+                                            trackerNameIndexMap);
+
+    EXPECT_FALSE(conditionTracker.isSliced());
+
+    std::vector<int> uids1 = {111, 1111, 11111};
+    string uid1_wl1 = "wl1_1";
+    std::vector<int> uids2 = {222, 2222, 22222};
+    string uid2_wl1 = "wl2_1";
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1);
+
+    // one matched start for uid1
+    vector<MatchingState> matcherState;
+    matcherState.push_back(MatchingState::kMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
+    vector<sp<ConditionTracker>> allPredicates;
+    vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+    vector<bool> changedCache(1, false);
+
+    conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+                                       changedCache);
+
+    EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+    EXPECT_TRUE(changedCache[0]);
+
+    // Now test query
+    ConditionKey queryKey;
+    conditionCache[0] = ConditionState::kNotEvaluated;
+
+    conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+    EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+    // another wake lock acquired by this uid
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1);
+
+    matcherState.clear();
+    matcherState.push_back(MatchingState::kMatched);
+    matcherState.push_back(MatchingState::kNotMatched);
+    conditionCache[0] = ConditionState::kNotEvaluated;
+    changedCache[0] = false;
+    conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+                                       changedCache);
+    EXPECT_FALSE(changedCache[0]);
+
+    // uid1 wake lock 1 release
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1,
+                      /*release=*/0);  // now release it.
+
+    matcherState.clear();
+    matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kMatched);
+    conditionCache[0] = ConditionState::kNotEvaluated;
+    changedCache[0] = false;
+    conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+                                       changedCache);
+    // nothing changes, because uid2 is still holding wl.
+    EXPECT_FALSE(changedCache[0]);
+
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1,
+                      /*acquire=*/0);  // now release it.
+    matcherState.clear();
+    matcherState.push_back(MatchingState::kNotMatched);
+    matcherState.push_back(MatchingState::kMatched);
+    conditionCache[0] = ConditionState::kNotEvaluated;
+    changedCache[0] = false;
+    conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
+                                       changedCache);
+    EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+    EXPECT_TRUE(changedCache[0]);
+
+    // query again
+    conditionCache[0] = ConditionState::kNotEvaluated;
+    conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+    EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestStopAll) {
+    std::vector<sp<ConditionTracker>> allConditions;
+    for (Position position : {Position::FIRST, Position::LAST}) {
+        SimplePredicate simplePredicate =
+                getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+                                         true /*output slice by uid*/, position);
+        string conditionName = "WL_HELD_BY_UID3";
+
+        unordered_map<int64_t, int> trackerNameIndexMap;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+        trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+        trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+        SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+                                                0 /*condition tracker index*/, simplePredicate,
+                                                trackerNameIndexMap);
+
+        std::vector<int> uids1 = {111, 1111, 11111};
+        std::vector<int> uids2 = {222, 2222, 22222};
+
+        LogEvent event1(/*uid=*/0, /*pid=*/0);
+        makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1);
+
+        // one matched start
+        vector<MatchingState> matcherState;
+        matcherState.push_back(MatchingState::kMatched);
+        matcherState.push_back(MatchingState::kNotMatched);
+        matcherState.push_back(MatchingState::kNotMatched);
+        vector<sp<ConditionTracker>> allPredicates;
+        vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+        vector<bool> changedCache(1, false);
+
+        conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+                                           changedCache);
+        if (position == Position::FIRST || position == Position::LAST) {
+            EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+        } else {
+            EXPECT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
+        }
+        EXPECT_TRUE(changedCache[0]);
+        {
+            if (position == Position::FIRST || position == Position::LAST) {
+                EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+            } else {
+                EXPECT_EQ(uids1.size(),
+                          conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+            }
+        }
+
+        // Now test query
+        const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName);
+        conditionCache[0] = ConditionState::kNotEvaluated;
+
+        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+        // another wake lock acquired by uid2
+        LogEvent event2(/*uid=*/0, /*pid=*/0);
+        makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+        matcherState.clear();
+        matcherState.push_back(MatchingState::kMatched);
+        matcherState.push_back(MatchingState::kNotMatched);
+        matcherState.push_back(MatchingState::kNotMatched);
+        conditionCache[0] = ConditionState::kNotEvaluated;
+        changedCache[0] = false;
+        conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+                                           changedCache);
+        if (position == Position::FIRST || position == Position::LAST) {
+            EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
+        } else {
+            EXPECT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
+        }
+        EXPECT_TRUE(changedCache[0]);
+        {
+            if (position == Position::FIRST || position == Position::LAST) {
+                EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+            } else {
+                EXPECT_EQ(uids2.size(),
+                          conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+            }
+        }
+
+        // TEST QUERY
+        const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName);
+        conditionCache[0] = ConditionState::kNotEvaluated;
+        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+
+        EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+        // stop all event
+        LogEvent event3(/*uid=*/0, /*pid=*/0);
+        makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+        matcherState.clear();
+        matcherState.push_back(MatchingState::kNotMatched);
+        matcherState.push_back(MatchingState::kNotMatched);
+        matcherState.push_back(MatchingState::kMatched);
+
+        conditionCache[0] = ConditionState::kNotEvaluated;
+        changedCache[0] = false;
+        conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+                                           changedCache);
+        EXPECT_TRUE(changedCache[0]);
+        EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+        {
+            if (position == Position::FIRST || position == Position::LAST) {
+                EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+            } else {
+                EXPECT_EQ(uids1.size() + uids2.size(),
+                          conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+                EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+            }
+        }
+
+        // TEST QUERY
+        const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName);
+        conditionCache[0] = ConditionState::kNotEvaluated;
+        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+
+        // TEST QUERY
+        const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName);
+        conditionCache[0] = ConditionState::kNotEvaluated;
+        conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+        EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+    }
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index 1eaaf08..e0eebef 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -53,185 +53,192 @@
 
 }  // namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
-//    const int num_buckets = 1;
-//    const int threshold = 3;
-//    auto config = CreateStatsdConfig(num_buckets, threshold);
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-//    sp<AnomalyTracker> anomalyTracker =
-//        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-//    std::vector<AttributionNodeInternal> attributions2 = {
-//        CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-//    std::vector<AttributionNodeInternal> attributions3 = {
-//        CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions4 = {
-//        CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions5 = {
-//        CreateAttribution(222, "GMSCoreModule1") };
-//
-//    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)111));
-//    HashableDimensionKey whatKey1({fieldValue1});
-//    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-//    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)222));
-//    HashableDimensionKey whatKey2({fieldValue2});
-//    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-//    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    // Fired alarm and refractory period end timestamp updated.
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
-//    const int num_buckets = 3;
-//    const int threshold = 3;
-//    auto config = CreateStatsdConfig(num_buckets, threshold);
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-//    sp<AnomalyTracker> anomalyTracker =
-//        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-//    std::vector<AttributionNodeInternal> attributions2 = {
-//        CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-//    std::vector<AttributionNodeInternal> attributions3 = {
-//        CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions4 = {
-//        CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions5 = {
-//        CreateAttribution(222, "GMSCoreModule1") };
-//
-//    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)111));
-//    HashableDimensionKey whatKey1({fieldValue1});
-//    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-//    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)222));
-//    HashableDimensionKey whatKey2({fieldValue2});
-//    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-//    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    // Fired alarm and refractory period end timestamp updated.
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-//    event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//}
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
+    const int num_buckets = 1;
+    const int threshold = 3;
+    auto config = CreateStatsdConfig(num_buckets, threshold);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    std::vector<int> attributionUids1 = {111};
+    std::vector<string> attributionTags1 = {"App1"};
+    std::vector<int> attributionUids2 = {111, 222};
+    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+    std::vector<int> attributionUids3 = {111, 333};
+    std::vector<string> attributionTags3 = {"App1", "App3"};
+    std::vector<int> attributionUids4 = {222, 333};
+    std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"};
+    std::vector<int> attributionUids5 = {222};
+    std::vector<string> attributionTags5 = {"GMSCoreModule1"};
+
+    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)111));
+    HashableDimensionKey whatKey1({fieldValue1});
+    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)222));
+    HashableDimensionKey whatKey2({fieldValue2});
+    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                            attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4,
+                                       "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5,
+                                       "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5,
+                                       "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Fired alarm and refractory period end timestamp updated.
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1,
+                                       attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+                                       attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4,
+                                       attributionTags4, "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5,
+                                       attributionTags5, "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5,
+                                       attributionTags5, "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5,
+                                       attributionTags5, "wl2");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+}
+
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
+    const int num_buckets = 3;
+    const int threshold = 3;
+    auto config = CreateStatsdConfig(num_buckets, threshold);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    std::vector<int> attributionUids1 = {111};
+    std::vector<string> attributionTags1 = {"App1"};
+    std::vector<int> attributionUids2 = {111, 222};
+    std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+
+    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)111));
+    HashableDimensionKey whatKey1({fieldValue1});
+    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                            attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Fired alarm and refractory period end timestamp updated.
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1,
+                                       "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+                                       attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2,
+                                       attributionTags2, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2,
+                                       attributionTags2, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2,
+                                       attributionTags2, "wl1");
+    processor->OnLogEvent(event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index 03a209a..fe45b55 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -69,414 +69,432 @@
     return config;
 }
 
-}  // namespace
+std::vector<int> attributionUids1 = {111, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
 
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-                                                      CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids2 = {111, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
 
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
-                                                      CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids3 = {222};
+std::vector<string> attributionTags3 = {"GMSCoreModule1"};
 
-std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")};
-
-MetricDimensionKey dimensionKey(
-    HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
-                                           (int32_t)0x02010101), Value((int32_t)111))}),
-    DEFAULT_DIMENSION_KEY);
+MetricDimensionKey dimensionKey1(
+        HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+                                               (int32_t)0x02010101),
+                                         Value((int32_t)111))}),
+        DEFAULT_DIMENSION_KEY);
 
 MetricDimensionKey dimensionKey2(
     HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
                                            (int32_t)0x02010101), Value((int32_t)222))}),
     DEFAULT_DIMENSION_KEY);
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
-//    const int num_buckets = 1;
-//    const uint64_t threshold_ns = NS_PER_SEC;
-//    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-//    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-//    sp<AnomalyTracker> anomalyTracker =
-//        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-//    auto screen_on_event = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-//    auto screen_off_event = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10);
-//    processor->OnLogEvent(screen_on_event.get());
-//    processor->OnLogEvent(screen_off_event.get());
-//
-//    // Acquire wakelock wl1.
-//    auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
-//    auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire wakelock wl1 within bucket #0.
-//    acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Release wakelock wl1. One anomaly detected.
-//    release_event = CreateReleaseWakelockEvent(
-//            attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire wakelock wl1.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112);
-//    processor->OnLogEvent(acquire_event.get());
-//    // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
-//    // end of the refractory period.
-//    const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-//    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-//              (uint32_t)alarmFiredTimestampSec0);
-//
-//    // Anomaly alarm fired.
-//    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-//            static_cast<uint32_t>(alarmFiredTimestampSec0));
-//    EXPECT_EQ(1u, alarmSet.size());
-//    processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Release wakelock wl1.
-//    release_event = CreateReleaseWakelockEvent(
-//            attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    // Within refractory period. No more anomaly detected.
-//    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire wakelock wl1.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs -  5 * NS_PER_SEC - 11);
-//    processor->OnLogEvent(acquire_event.get());
-//    const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
-//              (uint64_t)alarmFiredTimestampSec1);
-//
-//    // Release wakelock wl1.
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-//                static_cast<uint32_t>(alarmFiredTimestampSec1));
-//    EXPECT_EQ(0u, alarmSet.size());
-//
-//    // Acquire wakelock wl1 near the end of bucket #0.
-//    acquire_event = CreateAcquireWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
-//               anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    // Release the event at early bucket #1.
-//    release_event = CreateReleaseWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    // Anomaly detected when stopping the alarm. The refractory period does not change.
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Condition changes to false.
-//    screen_on_event = CreateScreenStateChangedEvent(
-//        android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//        bucketStartTimeNs + 2 * bucketSizeNs + 20);
-//    processor->OnLogEvent(screen_on_event.get());
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30);
-//    processor->OnLogEvent(acquire_event.get());
-//    // The condition is false. Do not start the alarm.
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Condition turns true.
-//    screen_off_event = CreateScreenStateChangedEvent(
-//        android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//        bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC);
-//    processor->OnLogEvent(screen_off_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    // Condition turns to false.
-//    screen_on_event = CreateScreenStateChangedEvent(
-//        android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//        bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1);
-//    processor->OnLogEvent(screen_on_event.get());
-//    // Condition turns to false. Cancelled the alarm.
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    //  Detected one anomaly.
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Condition turns to true again.
-//    screen_off_event = CreateScreenStateChangedEvent(
-//        android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//        bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2);
-//    processor->OnLogEvent(screen_off_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(refractory_period_sec +
-//                    (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
-//    const int num_buckets = 3;
-//    const uint64_t threshold_ns = NS_PER_SEC;
-//    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-//    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-//    sp<AnomalyTracker> anomalyTracker =
-//        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-//    auto screen_off_event = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-//    processor->OnLogEvent(screen_off_event.get());
-//
-//    // Acquire wakelock "wc1" in bucket #0.
-//    auto acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs -  NS_PER_SEC / 2 - 1);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Release wakelock "wc1" in bucket #0.
-//    auto release_event = CreateReleaseWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire wakelock "wc1" in bucket #1.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire wakelock "wc2" in bucket #2.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 2 *  bucketSizeNs) / NS_PER_SEC + 2,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    // Release wakelock "wc2" in bucket #2.
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//    EXPECT_EQ(refractory_period_sec +
-//                   (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-//    // Acquire wakelock "wc1" in bucket #2.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Release wakelock "wc1" in bucket #2.
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec +
-//                   (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4);
-//    processor->OnLogEvent(acquire_event.get());
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2);
-//    processor->OnLogEvent(release_event.get());
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//    // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
-//    EXPECT_EQ(refractory_period_sec +
-//                   (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
-//    const int num_buckets = 2;
-//    const uint64_t threshold_ns = 3 * NS_PER_SEC;
-//    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
-//    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
-//    config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-//    sp<AnomalyTracker> anomalyTracker =
-//        processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-//    auto screen_off_event = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-//    processor->OnLogEvent(screen_off_event.get());
-//
-//    // Acquire wakelock "wc1" in bucket #0.
-//    auto acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Acquire the wakelock "wc1" again.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1);
-//    processor->OnLogEvent(acquire_event.get());
-//    // The alarm does not change.
-//    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // Anomaly alarm fired late.
-//    const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
-//    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-//            static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
-//    EXPECT_EQ(1u, alarmSet.size());
-//    processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    auto release_event = CreateReleaseWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//    // Within the refractory period. No anomaly.
-//    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    // A new wakelock, but still within refractory period.
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC);
-//    // Still in the refractory period. No anomaly.
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-//              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    release_event = CreateReleaseWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4);
-//    processor->OnLogEvent(release_event.get());
-//    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-//    acquire_event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3);
-//    processor->OnLogEvent(acquire_event.get());
-//    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-//              anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
+}  // namespace
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
+    const int num_buckets = 1;
+    const uint64_t threshold_ns = NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_on_event = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screen_on_event.get());
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock wl1.
+    auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
+                                                    attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
+    auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
+                                                    attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire wakelock wl1 within bucket #0.
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
+                                               attributionTags2, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Release wakelock wl1. One anomaly detected.
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
+                                               attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire wakelock wl1.
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
+                                               attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
+    // end of the refractory period.
+    const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+              (uint32_t)alarmFiredTimestampSec0);
+
+    // Anomaly alarm fired.
+    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(alarmFiredTimestampSec0));
+    EXPECT_EQ(1u, alarmSet.size());
+    processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Release wakelock wl1.
+    release_event =
+            CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    // Within refractory period. No more anomaly detected.
+    EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire wakelock wl1.
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
+                                       attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
+              (uint64_t)alarmFiredTimestampSec1);
+
+    // Release wakelock wl1.
+    release_event =
+            CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
+                                       attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec +
+                      (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(alarmFiredTimestampSec1));
+    EXPECT_EQ(0u, alarmSet.size());
+
+    // Acquire wakelock wl1 near the end of bucket #0.
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
+                                               attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    // Release the event at early bucket #1.
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
+                                               attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    // Anomaly detected when stopping the alarm. The refractory period does not change.
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Condition changes to false.
+    screen_on_event =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screen_on_event.get());
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
+                                               attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    // The condition is false. Do not start the alarm.
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Condition turns true.
+    screen_off_event =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screen_off_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    // Condition turns to false.
+    screen_on_event =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screen_on_event.get());
+    // Condition turns to false. Cancelled the alarm.
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    //  Detected one anomaly.
+    EXPECT_EQ(refractory_period_sec +
+                      (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Condition turns to true again.
+    screen_off_event =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screen_off_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    release_event =
+            CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
+                                       attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(refractory_period_sec +
+                      (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
+    const int num_buckets = 3;
+    const uint64_t threshold_ns = NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock "wc1" in bucket #0.
+    auto acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Release wakelock "wc1" in bucket #0.
+    auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+                                                    attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire wakelock "wc1" in bucket #1.
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
+                                               attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
+                                               attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire wakelock "wc2" in bucket #2.
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+                                               attributionUids3, attributionTags3, "wl2");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Release wakelock "wc2" in bucket #2.
+    release_event =
+            CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+                                       attributionUids3, attributionTags3, "wl2");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    EXPECT_EQ(refractory_period_sec +
+                      (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+    // Acquire wakelock "wc1" in bucket #2.
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+                                       attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Release wakelock "wc1" in bucket #2.
+    release_event =
+            CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
+                                       attributionUids2, attributionTags2, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec +
+                      (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
+                              NS_PER_SEC +
+                      1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
+                                       attributionUids3, attributionTags3, "wl2");
+    processor->OnLogEvent(acquire_event.get());
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
+                                               attributionUids3, attributionTags3, "wl2");
+    processor->OnLogEvent(release_event.get());
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
+                                               attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+    // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
+    EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
+                      1,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
+    const int num_buckets = 2;
+    const uint64_t threshold_ns = 3 * NS_PER_SEC;
+    auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
+    int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
+    config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+    sp<AnomalyTracker> anomalyTracker =
+            processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+    auto screen_off_event = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screen_off_event.get());
+
+    // Acquire wakelock "wc1" in bucket #0.
+    auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
+                                                    attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Acquire the wakelock "wc1" again.
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    // The alarm does not change.
+    EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // Anomaly alarm fired late.
+    const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+    auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+            static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
+    EXPECT_EQ(1u, alarmSet.size());
+    processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+                                               attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+                                                    attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+    // Within the refractory period. No anomaly.
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    // A new wakelock, but still within refractory period.
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
+                                               attributionUids1, attributionTags1, "wl1");
+    // Still in the refractory period. No anomaly.
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+              anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    release_event =
+            CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(release_event.get());
+    EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+    acquire_event =
+            CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
+                                       attributionUids1, attributionTags1, "wl1");
+    processor->OnLogEvent(acquire_event.get());
+    EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+              anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 6051174..9e743f7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -53,367 +53,318 @@
     return config;
 }
 
+// GMS core node is in the middle.
+std::vector<int> attributionUids1 = {111, 222, 333};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "App3"};
+
+// GMS core node is the last one.
+std::vector<int> attributionUids2 = {111, 333, 222};
+std::vector<string> attributionTags2 = {"App1", "App3", "GMSCoreModule1"};
+
+// GMS core node is the first one.
+std::vector<int> attributionUids3 = {222, 333};
+std::vector<string> attributionTags3 = {"GMSCoreModule1", "App3"};
+
+// Single GMS core node.
+std::vector<int> attributionUids4 = {222};
+std::vector<string> attributionTags4 = {"GMSCoreModule1"};
+
+// GMS core has another uid.
+std::vector<int> attributionUids5 = {111, 444, 333};
+std::vector<string> attributionTags5 = {"App1", "GMSCoreModule2", "App3"};
+
+// Multiple GMS core nodes.
+std::vector<int> attributionUids6 = {444, 222};
+std::vector<string> attributionTags6 = {"GMSCoreModule2", "GMSCoreModule1"};
+
+// No GMS core nodes
+std::vector<int> attributionUids7 = {111, 333};
+std::vector<string> attributionTags7 = {"App1", "App3"};
+
+std::vector<int> attributionUids8 = {111};
+std::vector<string> attributionTags8 = {"App1"};
+
+// GMS core node with isolated uid.
+const int isolatedUid = 666;
+std::vector<int> attributionUids9 = {isolatedUid};
+std::vector<string> attributionTags9 = {"GMSCoreModule3"};
+
+std::vector<int> attributionUids10 = {isolatedUid};
+std::vector<string> attributionTags10 = {"GMSCoreModule1"};
+
 }  // namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
-//    auto config = CreateStatsdConfig(Position::FIRST);
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//    // Here it assumes that GMS core has two uids.
-//    processor->getUidMap()->updateMap(
-//            1, {222, 444, 111, 333}, {1, 1, 2, 2},
-//            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-//            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-//             String16("APP3")},
-//            {String16(""), String16(""), String16(""), String16("")});
-//
-//    // GMS core node is in the middle.
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(222, "GMSCoreModule1"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // GMS core node is the last one.
-//    std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(333, "App3"),
-//                                                          CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // GMS core node is the first one.
-//    std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // Single GMS core node.
-//    std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // GMS core has another uid.
-//    std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(444, "GMSCoreModule2"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // Multiple GMS core nodes.
-//    std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-//                                                          CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // No GMS core nodes.
-//    std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-//    // GMS core node with isolated uid.
-//    const int isolatedUid = 666;
-//    std::vector<AttributionNodeInternal> attributions9 = {
-//            CreateAttribution(isolatedUid, "GMSCoreModule3")};
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    // Events 1~4 are in the 1st bucket.
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 2));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 200));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-//    // Events 5~8 are in the 3rd bucket.
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-//    events.push_back(CreateIsolatedUidChangedEvent(
-//        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-//    events.push_back(CreateIsolatedUidChangedEvent(
-//        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-//    sortLogEventsByTimestamp(&events);
-//
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(countMetrics.data_size(), 4);
-//
-//    auto data = countMetrics.data(0);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111,
-//            "App1");
-//    EXPECT_EQ(data.bucket_info_size(), 2);
-//    EXPECT_EQ(data.bucket_info(0).count(), 2);
-//    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-//    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(1).count(), 1);
-//    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//
-//    data = countMetrics.data(1);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-//            "GMSCoreModule1");
-//    EXPECT_EQ(data.bucket_info_size(), 2);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-//    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(1).count(), 1);
-//    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-//
-//    data = countMetrics.data(2);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-//            "GMSCoreModule3");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
-//
-//    data = countMetrics.data(3);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 444,
-//            "GMSCoreModule2");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-//    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//}
-//
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
-//    auto config = CreateStatsdConfig(Position::ALL);
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//    // Here it assumes that GMS core has two uids.
-//    processor->getUidMap()->updateMap(
-//            1, {222, 444, 111, 333}, {1, 1, 2, 2},
-//            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-//            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-//             String16("APP3")},
-//            {String16(""), String16(""), String16(""), String16("")});
-//
-//    // GMS core node is in the middle.
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(222, "GMSCoreModule1"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // GMS core node is the last one.
-//    std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(333, "App3"),
-//                                                          CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // GMS core node is the first one.
-//    std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // Single GMS core node.
-//    std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // GMS core has another uid.
-//    std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(444, "GMSCoreModule2"),
-//                                                          CreateAttribution(333, "App3")};
-//
-//    // Multiple GMS core nodes.
-//    std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-//                                                          CreateAttribution(222, "GMSCoreModule1")};
-//
-//    // No GMS core nodes.
-//    std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-//                                                          CreateAttribution(333, "App3")};
-//    std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-//    // GMS core node with isolated uid.
-//    const int isolatedUid = 666;
-//    std::vector<AttributionNodeInternal> attributions9 = {
-//            CreateAttribution(isolatedUid, "GMSCoreModule1")};
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    // Events 1~4 are in the 1st bucket.
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 2));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions2, "wl1", bucketStartTimeNs + 200));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-//    // Events 5~8 are in the 3rd bucket.
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-//    events.push_back(CreateAcquireWakelockEvent(
-//        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-//    events.push_back(CreateIsolatedUidChangedEvent(
-//        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-//    events.push_back(CreateIsolatedUidChangedEvent(
-//        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-//    sortLogEventsByTimestamp(&events);
-//
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(countMetrics.data_size(), 6);
-//
-//    auto data = countMetrics.data(0);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(1).count());
-//    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//              data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
-//              data.bucket_info(1).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-//    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//
-//    data = countMetrics.data(2);
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(bucketStartTimeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(4);
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(bucketStartTimeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(5);
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-//    ValidateUidDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-//    ValidateAttributionUidAndTagDimension(
-//        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-//    EXPECT_EQ(data.bucket_info_size(), 1);
-//    EXPECT_EQ(data.bucket_info(0).count(), 1);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
+    auto config = CreateStatsdConfig(Position::FIRST);
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    // Here it assumes that GMS core has two uids.
+    processor->getUidMap()->updateMap(
+            1, {222, 444, 111, 333}, {1, 1, 2, 2},
+            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+             String16("APP3")},
+            {String16(""), String16(""), String16(""), String16("")});
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    // Events 1~4 are in the 1st bucket.
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                                attributionTags1, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+                                                attributionTags2, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+                                                attributionUids3, attributionTags3, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+                                                attributionTags4, "wl1"));
+
+    // Events 5~8 are in the 3rd bucket.
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+                                                attributionUids5, attributionTags5, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+                                                attributionUids6, attributionTags6, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+                                                attributionUids7, attributionTags7, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+                                                attributionUids8, attributionTags8, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+                                                attributionUids9, attributionTags9, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+                                                attributionUids9, attributionTags9, "wl2"));
+    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+                                                   isolatedUid, true /*is_create*/));
+    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+                                                   isolatedUid, false /*is_create*/));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(countMetrics.data_size(), 4);
+
+    auto data = countMetrics.data(0);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    EXPECT_EQ(data.bucket_info_size(), 2);
+    EXPECT_EQ(data.bucket_info(0).count(), 2);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).count(), 1);
+    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+              bucketStartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+
+    data = countMetrics.data(1);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    EXPECT_EQ(data.bucket_info_size(), 2);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).count(), 1);
+    EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+
+    data = countMetrics.data(2);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+              bucketStartTimeNs + 3 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+
+    data = countMetrics.data(3);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          "GMSCoreModule2");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+              bucketStartTimeNs + 2 * bucketSizeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+}
+
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
+    auto config = CreateStatsdConfig(Position::ALL);
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    // Here it assumes that GMS core has two uids.
+    processor->getUidMap()->updateMap(
+            1, {222, 444, 111, 333}, {1, 1, 2, 2},
+            {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+             String16("APP3")},
+            {String16(""), String16(""), String16(""), String16("")});
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    // Events 1~4 are in the 1st bucket.
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                                attributionTags1, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+                                                attributionTags2, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+                                                attributionUids3, attributionTags3, "wl1"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+                                                attributionTags4, "wl1"));
+
+    // Events 5~8 are in the 3rd bucket.
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+                                                attributionUids5, attributionTags5, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+                                                attributionUids6, attributionTags6, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+                                                attributionUids7, attributionTags7, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+                                                attributionUids8, attributionTags8, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+                                                attributionUids10, attributionTags10, "wl2"));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+                                                attributionUids10, attributionTags10, "wl2"));
+    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+                                                   isolatedUid, true /*is_create*/));
+    events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+                                                   isolatedUid, false /*is_create*/));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(countMetrics.data_size(), 6);
+
+    auto data = countMetrics.data(0);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+              data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+
+    data = countMetrics.data(2);
+    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          "GMSCoreModule2");
+    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+                                          android::util::WAKELOCK_STATE_CHANGED, 222,
+                                          "GMSCoreModule1");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(5);
+    ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+                                          android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+                                          android::util::WAKELOCK_STATE_CHANGED, 444,
+                                          "GMSCoreModule2");
+    ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+                                          android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index f8edee5..102bb1e 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -56,54 +56,54 @@
 
 }  // namespace
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ConfigTtlE2eTest, TestCountMetric) {
-//    const int num_buckets = 1;
-//    const int threshold = 3;
-//    auto config = CreateStatsdConfig(num_buckets, threshold);
-//    const uint64_t alert_id = config.alert(0).id();
-//    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-//
-//    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)111));
-//    HashableDimensionKey whatKey1({fieldValue1});
-//    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-//    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-//                           Value((int32_t)222));
-//    HashableDimensionKey whatKey2({fieldValue2});
-//    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-//    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateAcquireWakelockEvent(attributions1, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateAcquireWakelockEvent(
-//        attributions1, "wl1", bucketStartTimeNs + 25 * bucketSizeNs + 2);
-//    processor->OnLogEvent(event.get());
-//
-//    EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
-//              processor->mMetricsManagers.begin()->second->getTtlEndNs());
-//
-//    // Clear the data stored on disk as a result of the ttl.
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
-//                                ADB_DUMP, FAST, &buffer);
-//}
+TEST(ConfigTtlE2eTest, TestCountMetric) {
+    const int num_buckets = 1;
+    const int threshold = 3;
+    auto config = CreateStatsdConfig(num_buckets, threshold);
+    const uint64_t alert_id = config.alert(0).id();
+    const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
 
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    std::vector<int> attributionUids1 = {111};
+    std::vector<string> attributionTags1 = {"App1"};
+
+    FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)111));
+    HashableDimensionKey whatKey1({fieldValue1});
+    MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+    FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+                           Value((int32_t)222));
+    HashableDimensionKey whatKey2({fieldValue2});
+    MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                            attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids1,
+                                       attributionTags1, "wl2");
+    processor->OnLogEvent(event.get());
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * bucketSizeNs + 2, attributionUids1,
+                                       attributionTags1, "wl1");
+    processor->OnLogEvent(event.get());
+
+    EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
+              processor->mMetricsManagers.begin()->second->getTtlEndNs());
+
+    // Clear the data stored on disk as a result of the ttl.
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
+                            ADB_DUMP, FAST, &buffer);
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index a1f74a6..2cd7854 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -27,773 +27,775 @@
 
 #ifdef __ANDROID__
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-///**
-// * Test a count metric that has one slice_by_state with no primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and no entries in mStateGroupMap.
-//
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedState) {
-//    // Initialize config.
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-//
-//    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-//    *config.add_atom_matcher() = syncStartMatcher;
-//
-//    auto state = CreateScreenState();
-//    *config.add_state() = state;
-//
-//    // Create count metric that slices by screen state.
-//    int64_t metricId = 123456;
-//    auto countMetric = config.add_count_metric();
-//    countMetric->set_id(metricId);
-//    countMetric->set_what(syncStartMatcher.id());
-//    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-//    countMetric->add_slice_by_state(state.id());
-//
-//    // Initialize StatsLogProcessor.
-//    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-//    const uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-//    // Check that CountMetricProducer was initialized correctly.
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-//    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-//
-//    // Check that StateTrackers were initialized correctly.
-//    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-//    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-//    /*
-//               bucket #1                      bucket #2
-//    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-//    |-----------------------------|-----------------------------|--
-//            x                x         x    x        x      x       (syncStartEvents)
-//          |                                       |                 (ScreenIsOnEvent)
-//                   |     |                                          (ScreenIsOffEvent)
-//                                                        |           (ScreenUnknownEvent)
-//    */
-//    // Initialize log events - first bucket.
-//    int appUid = 123;
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 50 * NS_PER_SEC));  // 1:00
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 75 * NS_PER_SEC));  // 1:25
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
-//
-//    // Initialize log events - second bucket.
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 350 * NS_PER_SEC));  // 6:00
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 400 * NS_PER_SEC));  // 6:50
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 450 * NS_PER_SEC));  // 7:40
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 475 * NS_PER_SEC));  // 8:05
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-//                                          bucketStartTimeNs + 500 * NS_PER_SEC));  // 8:30
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 520 * NS_PER_SEC));  // 8:50
-//
-//    // Send log events to StatsLogProcessor.
-//    for (auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    // Check dump report.
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-//                            FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-//    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    // For each CountMetricData, check StateValue info is correct and buckets
-//    // have correct counts.
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(1, data.bucket_info(1).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(1);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(2);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a mapping and no
-// * primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
-// *
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
-//    // Initialize config.
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-//
-//    auto syncStartMatcher = CreateSyncStartAtomMatcher();
-//    *config.add_atom_matcher() = syncStartMatcher;
-//
-//    auto state = CreateScreenStateWithOnOffMap();
-//    *config.add_state() = state;
-//
-//    // Create count metric that slices by screen state with on/off map.
-//    int64_t metricId = 123456;
-//    auto countMetric = config.add_count_metric();
-//    countMetric->set_id(metricId);
-//    countMetric->set_what(syncStartMatcher.id());
-//    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-//    countMetric->add_slice_by_state(state.id());
-//
-//    // Initialize StatsLogProcessor.
-//    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-//    const uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-//    // Check that StateTrackers were initialized correctly.
-//    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-//    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-//    // Check that CountMetricProducer was initialized correctly.
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-//    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-//
-//    StateMap map = state.map();
-//    for (auto group : map.group()) {
-//        for (auto value : group.value()) {
-//            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-//                      group.group_id());
-//        }
-//    }
-//
-//    /*
-//               bucket #1                      bucket #2
-//    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-//    |-----------------------------|-----------------------------|--
-//      x   x     x       x    x   x      x         x         x       (syncStartEvents)
-//     -----------------------------------------------------------SCREEN_OFF events
-//       |                                                            (ScreenStateUnknownEvent = 0)
-//             |                  |                                   (ScreenStateOffEvent = 1)
-//                          |                                         (ScreenStateDozeEvent = 3)
-//                                                |                   (ScreenStateDozeSuspendEvent = 4)
-//     -----------------------------------------------------------SCREEN_ON events
-//                   |                                       |        (ScreenStateOnEvent = 2)
-//                      |                                             (ScreenStateVrEvent = 5)
-//                                            |                       (ScreenStateOnSuspendEvent = 6)
-//    */
-//    // Initialize log events - first bucket.
-//    int appUid = 123;
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-//                                          bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
-//                                          bucketStartTimeNs + 180 * NS_PER_SEC));  // 3:10
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-//                                          bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
-//
-//    // Initialize log events - second bucket.
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-//                                          bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
-//    events.push_back(CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND,
-//            bucketStartTimeNs + 430 * NS_PER_SEC));  // 7:20
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
-//    events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-//                                          bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
-//
-//    // Send log events to StatsLogProcessor.
-//    for (auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    // Check dump report.
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-//                            FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-//    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    // For each CountMetricData, check StateValue info is correct and buckets
-//    // have correct counts.
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(1);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(4, data.bucket_info(0).count());
-//    EXPECT_EQ(2, data.bucket_info(1).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(2);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(1, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a primary field.
-//
-// * Once the CountMetricProducer is initialized, it should have one
-// * MetricStateLink stored. State querying using a non-empty primary key
-// * should also work as intended.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
-//    // Initialize config.
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-//
-//    auto appCrashMatcher =
-//            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-//    *config.add_atom_matcher() = appCrashMatcher;
-//
-//    auto state = CreateUidProcessState();
-//    *config.add_state() = state;
-//
-//    // Create count metric that slices by uid process state.
-//    int64_t metricId = 123456;
-//    auto countMetric = config.add_count_metric();
-//    countMetric->set_id(metricId);
-//    countMetric->set_what(appCrashMatcher.id());
-//    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-//    countMetric->add_slice_by_state(state.id());
-//    MetricStateLink* stateLink = countMetric->add_state_link();
-//    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-//    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-//    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-//    auto fieldsInState = stateLink->mutable_fields_in_state();
-//    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-//    // Initialize StatsLogProcessor.
-//    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-//    const uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-//    // Check that StateTrackers were initialized correctly.
-//    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-//    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-//    // Check that CountMetricProducer was initialized correctly.
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
-//    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-//    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-//    /*
-//    NOTE: "1" or "2" represents the uid associated with the state/app crash event
-//               bucket #1                      bucket #2
-//    |     1     2     3     4     5     6     7     8     9     10
-//    |-----------------------------|-----------------------------|--
-//      1   1     1       1    1   2      1         1          2      (AppCrashEvents)
-//     -----------------------------------------------------------PROCESS STATE events
-//             1                  2                                   (ProcessStateTopEvent = 1002)
-//                          1                 1                       (ProcessStateForegroundServiceEvent = 1003)
-//                                                2                   (ProcessStateImportantBackgroundEvent = 1006)
-//        1          1                                       1        (ProcessStateImportantForegroundEvent = 1005)
-//
-//    Based on the diagram above, an AppCrashEvent querying for process state value would return:
-//    - StateTracker::kStateUnknown
-//    - Important foreground
-//    - Top
-//    - Important foreground
-//    - Foreground service
-//    - Top (both the app crash and state still have matching uid = 2)
-//
-//    - Foreground service
-//    - Foreground service
-//    - Important background
-//    */
-//    // Initialize log events - first bucket.
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(
-//            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
-//    events.push_back(
-//            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//            bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-//            bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//            bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-//    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-//                                                 bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
-//
-//    // Initialize log events - second bucket.
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-//            bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-//            bucketStartTimeNs + 430 * NS_PER_SEC));  // 7:20
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
-//    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-//                                                 bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
-//
-//    // Send log events to StatsLogProcessor.
-//    for (auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    // Check dump report.
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-//                            FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-//    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    // For each CountMetricData, check StateValue info is correct and buckets
-//    // have correct counts.
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(1);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(2);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(2, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(3);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(2, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(4);
-//    EXPECT_EQ(1, data.slice_by_state_size());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-//TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
-//    // Initialize config.
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
-//
-//    auto appCrashMatcher =
-//            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-//    *config.add_atom_matcher() = appCrashMatcher;
-//
-//    auto state1 = CreateScreenStateWithOnOffMap();
-//    *config.add_state() = state1;
-//    auto state2 = CreateUidProcessState();
-//    *config.add_state() = state2;
-//
-//    // Create count metric that slices by screen state with on/off map and
-//    // slices by uid process state.
-//    int64_t metricId = 123456;
-//    auto countMetric = config.add_count_metric();
-//    countMetric->set_id(metricId);
-//    countMetric->set_what(appCrashMatcher.id());
-//    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-//    countMetric->add_slice_by_state(state1.id());
-//    countMetric->add_slice_by_state(state2.id());
-//    MetricStateLink* stateLink = countMetric->add_state_link();
-//    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-//    auto fieldsInWhat = stateLink->mutable_fields_in_what();
-//    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-//    auto fieldsInState = stateLink->mutable_fields_in_state();
-//    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-//    // Initialize StatsLogProcessor.
-//    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
-//    const uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-//    // Check that StateTrackers were properly initialized.
-//    EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
-//    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-//    // Check that CountMetricProducer was initialized correctly.
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-//    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
-//    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-//    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-//    StateMap map = state1.map();
-//    for (auto group : map.group()) {
-//        for (auto value : group.value()) {
-//            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-//                      group.group_id());
-//        }
-//    }
-//
-//    /*
-//               bucket #1                      bucket #2
-//    |     1     2     3     4     5     6     7     8     9     10 (minutes)
-//    |-----------------------------|-----------------------------|--
-//      1   1     1       1    1   2      1         1           2     (AppCrashEvents)
-//     -----------------------------------------------------------SCREEN_OFF events
-//       |                                                            (ScreenStateUnknownEvent = 0)
-//             |                                  |                   (ScreenStateOffEvent = 1)
-//                          |                                         (ScreenStateDozeEvent = 3)
-//     -----------------------------------------------------------SCREEN_ON events
-//                    |                                    |          (ScreenStateOnEvent = 2)
-//                                            |                       (ScreenStateOnSuspendEvent = 6)
-//     -----------------------------------------------------------PROCESS STATE events
-//             1                  2                                   (ProcessStateTopEvent = 1002)
-//                                          1                         (ProcessStateForegroundServiceEvent = 1003)
-//                                               2                    (ProcessStateImportantBackgroundEvent = 1006)
-//     1             1                                       1        (ProcessStateImportantForegroundEvent = 1005)
-//
-//     Based on the diagram above, Screen State / Process State pairs for each
-//     AppCrashEvent are:
-//     - StateTracker::kStateUnknown / important foreground
-//     - off / important foreground
-//     - off / Top
-//     - on / important foreground
-//     - off / important foreground
-//     - off / top
-//
-//     - off / important foreground
-//     - off / foreground service
-//     - on / important background
-//
-//    */
-//    // Initialize log events - first bucket.
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 5 * NS_PER_SEC));  // 0:15
-//    events.push_back(
-//            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC));  // 0:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-//                                          bucketStartTimeNs + 30 * NS_PER_SEC));  // 0:40
-//    events.push_back(
-//            CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC));  // 1:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//            bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 90 * NS_PER_SEC));  // 1:40
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 120 * NS_PER_SEC));  // 2:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 150 * NS_PER_SEC));  // 2:40
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 160 * NS_PER_SEC));  // 2:50
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 200 * NS_PER_SEC));  // 3:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-//                                          bucketStartTimeNs + 210 * NS_PER_SEC));  // 3:40
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 250 * NS_PER_SEC));  // 4:20
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-//            bucketStartTimeNs + 280 * NS_PER_SEC));  // 4:50
-//    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-//                                                 bucketStartTimeNs + 285 * NS_PER_SEC));  // 4:55
-//
-//    // Initialize log events - second bucket.
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 360 * NS_PER_SEC));  // 6:10
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-//            bucketStartTimeNs + 380 * NS_PER_SEC));  // 6:30
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-//                                          bucketStartTimeNs + 390 * NS_PER_SEC));  // 6:40
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-//            bucketStartTimeNs + 420 * NS_PER_SEC));  // 7:10
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 440 * NS_PER_SEC));  // 7:30
-//    events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-//                                                 bucketStartTimeNs + 450 * NS_PER_SEC));  // 7:40
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 520 * NS_PER_SEC));  // 8:50
-//    events.push_back(CreateUidProcessStateChangedEvent(
-//            1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-//            bucketStartTimeNs + 540 * NS_PER_SEC));  // 9:10
-//    events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-//                                                 bucketStartTimeNs + 570 * NS_PER_SEC));  // 9:40
-//
-//    // Send log events to StatsLogProcessor.
-//    for (auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    // Check dump report.
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-//                            FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-//    EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    // For each CountMetricData, check StateValue info is correct and buckets
-//    // have correct counts.
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(1);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_value());
-//    EXPECT_EQ(-1, data.slice_by_state(0).value());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(2);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-//    EXPECT_EQ(2, data.bucket_info_size());
-//    EXPECT_EQ(2, data.bucket_info(0).count());
-//    EXPECT_EQ(1, data.bucket_info(1).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(3);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(4);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//
-//    data = reports.reports(0).metrics(0).count_metrics().data(5);
-//    EXPECT_EQ(2, data.slice_by_state_size());
-//    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-//    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-//    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-//    EXPECT_TRUE(data.slice_by_state(1).has_value());
-//    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(2, data.bucket_info(0).count());
-//}
+/**
+* Test a count metric that has one slice_by_state with no primary fields.
+*
+* Once the CountMetricProducer is initialized, it has one atom id in
+* mSlicedStateAtoms and no entries in mStateGroupMap.
+
+* One StateTracker tracks the state atom, and it has one listener which is the
+* CountMetricProducer that was initialized.
+*/
+TEST(CountMetricE2eTest, TestSlicedState) {
+    // Initialize config.
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto syncStartMatcher = CreateSyncStartAtomMatcher();
+    *config.add_atom_matcher() = syncStartMatcher;
+
+    auto state = CreateScreenState();
+    *config.add_state() = state;
+
+    // Create count metric that slices by screen state.
+    int64_t metricId = 123456;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(metricId);
+    countMetric->set_what(syncStartMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+    countMetric->add_slice_by_state(state.id());
+
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+    // Check that CountMetricProducer was initialized correctly.
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+
+    // Check that StateTrackers were initialized correctly.
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+    /*
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10 (minutes)
+    |-----------------------------|-----------------------------|--
+            x                x         x    x        x      x       (syncStartEvents)
+          |                                       |                 (ScreenIsOnEvent)
+                   |     |                                          (ScreenIsOffEvent)
+                                                        |           (ScreenUnknownEvent)
+    */
+    // Initialize log events - first bucket.
+    std::vector<int> attributionUids1 = {123};
+    std::vector<string> attributionTags1 = {"App1"};
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 50 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 1:00
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 1:25
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 150 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 2:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 200 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 3:30
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 4:20
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 6:00
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 6:50
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 450 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 7:40
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 8:05
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 500 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN));  // 8:30
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 8:50
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+              data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+/**
+ * Test a count metric that has one slice_by_state with a mapping and no
+ * primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
+ *
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
+    // Initialize config.
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto syncStartMatcher = CreateSyncStartAtomMatcher();
+    *config.add_atom_matcher() = syncStartMatcher;
+
+    auto state = CreateScreenStateWithOnOffMap();
+    *config.add_state() = state;
+
+    // Create count metric that slices by screen state with on/off map.
+    int64_t metricId = 123456;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(metricId);
+    countMetric->set_what(syncStartMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+    countMetric->add_slice_by_state(state.id());
+
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+    // Check that StateTrackers were initialized correctly.
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+    // Check that CountMetricProducer was initialized correctly.
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+
+    StateMap map = state.map();
+    for (auto group : map.group()) {
+        for (auto value : group.value()) {
+            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+                      group.group_id());
+        }
+    }
+
+    /*
+               bucket #1                      bucket #2
+    |     1     2     3     4     5     6     7     8     9     10 (minutes)
+    |-----------------------------|-----------------------------|--
+      x   x     x       x    x   x      x         x         x       (syncStartEvents)
+     -----------------------------------------------------------SCREEN_OFF events
+       |                                                            (ScreenStateUnknownEvent = 0)
+             |                  |                                   (ScreenStateOffEvent = 1)
+                          |                                         (ScreenStateDozeEvent = 3)
+                                                |                   (ScreenStateDozeSuspendEvent =
+    4)
+     -----------------------------------------------------------SCREEN_ON events
+                   |                                       |        (ScreenStateOnEvent = 2)
+                      |                                             (ScreenStateVrEvent = 5)
+                                            |                       (ScreenStateOnSuspendEvent = 6)
+    */
+    // Initialize log events - first bucket.
+    std::vector<int> attributionUids1 = {123};
+    std::vector<string> attributionTags1 = {"App1"};
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 0:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 30 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN));  // 0:40
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 1:10
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 90 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:40
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 2:10
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 150 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 180 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_VR));  // 3:10
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 3:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 210 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 3:40
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 4:20
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 280 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 4:50
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 6:10
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 390 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND));  // 6:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 430 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND));  // 7:20
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 7:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 540 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 9:10
+    events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1,
+                                          attributionTags1, "sync_name"));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(4, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+}
+
+/**
+* Test a count metric that has one slice_by_state with a primary field.
+
+* Once the CountMetricProducer is initialized, it should have one
+* MetricStateLink stored. State querying using a non-empty primary key
+* should also work as intended.
+*/
+TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
+    // Initialize config.
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto appCrashMatcher =
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+    *config.add_atom_matcher() = appCrashMatcher;
+
+    auto state = CreateUidProcessState();
+    *config.add_state() = state;
+
+    // Create count metric that slices by uid process state.
+    int64_t metricId = 123456;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(metricId);
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+    countMetric->add_slice_by_state(state.id());
+    MetricStateLink* stateLink = countMetric->add_state_link();
+    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+    auto fieldsInWhat = stateLink->mutable_fields_in_what();
+    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+    auto fieldsInState = stateLink->mutable_fields_in_state();
+    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+    // Check that StateTrackers were initialized correctly.
+    EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+    // Check that CountMetricProducer was initialized correctly.
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+    /*
+    NOTE: "1" or "2" represents the uid associated with the state/app crash event
+               bucket #1               bucket #2
+    |    1    2    3    4    5    6    7    8    9    10
+    |------------------------|-------------------------|--
+      1  1    1      1   1  2     1        1        2    (AppCrashEvents)
+     -----------------------------------------------------PROCESS STATE events
+           1               2                             (TopEvent = 1002)
+                       1             1                   (ForegroundServiceEvent = 1003)
+                                         2               (ImportantBackgroundEvent = 1006)
+       1          1                               1      (ImportantForegroundEvent = 1005)
+
+    Based on the diagram above, an AppCrashEvent querying for process state value would return:
+    - StateTracker::kStateUnknown
+    - Important foreground
+    - Top
+    - Important foreground
+    - Foreground service
+    - Top (both the app crash and state still have matching uid = 2)
+
+    - Foreground service
+    - Foreground service
+    - Important background
+    */
+    // Initialize log events - first bucket.
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/));  // 0:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 0:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/));  // 1:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 1:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/));  // 2:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 2:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/));  // 3:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 3:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/));  // 4:20
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 4:50
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/));  // 6:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 6:40
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 7:20
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/));  // 7:30
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 9:10
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(3);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(4);
+    EXPECT_EQ(1, data.slice_by_state_size());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
+    // Initialize config.
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto appCrashMatcher =
+            CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+    *config.add_atom_matcher() = appCrashMatcher;
+
+    auto state1 = CreateScreenStateWithOnOffMap();
+    *config.add_state() = state1;
+    auto state2 = CreateUidProcessState();
+    *config.add_state() = state2;
+
+    // Create count metric that slices by screen state with on/off map and
+    // slices by uid process state.
+    int64_t metricId = 123456;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(metricId);
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+    countMetric->add_slice_by_state(state1.id());
+    countMetric->add_slice_by_state(state2.id());
+    MetricStateLink* stateLink = countMetric->add_state_link();
+    stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+    auto fieldsInWhat = stateLink->mutable_fields_in_what();
+    *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+    auto fieldsInState = stateLink->mutable_fields_in_state();
+    *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+    // Initialize StatsLogProcessor.
+    const uint64_t bucketStartTimeNs = 10000000000;  // 0:10
+    const uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+    // Check that StateTrackers were properly initialized.
+    EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+    EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+    // Check that CountMetricProducer was initialized correctly.
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
+    EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+    EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+    StateMap map = state1.map();
+    for (auto group : map.group()) {
+        for (auto value : group.value()) {
+            EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+                      group.group_id());
+        }
+    }
+
+    /*
+                 bucket #1                      bucket #2
+      |    1    2    3    4    5    6    7    8    9    10 (minutes)
+      |------------------------|------------------------|--
+        1  1    1     1    1  2     1        1         2   (AppCrashEvents)
+       ---------------------------------------------------SCREEN_OFF events
+         |                                                 (ScreenUnknownEvent = 0)
+             |                              |              (ScreenOffEvent = 1)
+                        |                                  (ScreenDozeEvent = 3)
+       ---------------------------------------------------SCREEN_ON events
+                   |                              |        (ScreenOnEvent = 2)
+                                        |                  (ScreenOnSuspendEvent = 6)
+       ---------------------------------------------------PROCESS STATE events
+             1               2                             (TopEvent = 1002)
+                                      1                    (ForegroundServiceEvent = 1003)
+                                            2              (ImportantBackgroundEvent = 1006)
+       1          1                                   1    (ImportantForegroundEvent = 1005)
+
+       Based on the diagram above, Screen State / Process State pairs for each
+       AppCrashEvent are:
+       - StateTracker::kStateUnknown / important foreground
+       - off / important foreground
+       - off / Top
+       - on / important foreground
+       - off / important foreground
+       - off / top
+
+       - off / important foreground
+       - off / foreground service
+       - on / important background
+
+      */
+    // Initialize log events - first bucket.
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 0:15
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/));  // 0:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 30 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN));  // 0:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/));  // 1:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 1:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 90 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 1:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/));  // 2:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 2:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 160 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 2:50
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/));  // 3:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 210 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_DOZE));  // 3:40
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/));  // 4:20
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_TOP));  // 4:50
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/));  // 4:55
+
+    // Initialize log events - second bucket.
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/));  // 6:10
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE));  // 6:30
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 390 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND));  // 6:40
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND));  // 7:10
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 440 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_OFF));  // 7:30
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/));  // 7:40
+    events.push_back(CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 520 * NS_PER_SEC,
+            android::view::DisplayStateEnum::DISPLAY_STATE_ON));  // 8:50
+    events.push_back(CreateUidProcessStateChangedEvent(
+            bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+            android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND));  // 9:10
+    events.push_back(
+            CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/));  // 9:40
+
+    // Send log events to StatsLogProcessor.
+    for (auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    // Check dump report.
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+    EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    // For each CountMetricData, check StateValue info is correct and buckets
+    // have correct counts.
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(1);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_value());
+    EXPECT_EQ(-1, data.slice_by_state(0).value());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(2);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(3);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(4);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+
+    data = reports.reports(0).metrics(0).count_metrics().data(5);
+    EXPECT_EQ(2, data.slice_by_state_size());
+    EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+    EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+    EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+    EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+    EXPECT_TRUE(data.slice_by_state(1).has_value());
+    EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(2, data.bucket_info(0).count());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 8eb5f69..b586b06 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -26,688 +26,688 @@
 
 #ifdef __ANDROID__
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(DurationMetricE2eTest, TestOneBucket) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-//    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-//    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-//    *config.add_atom_matcher() = screenOnMatcher;
-//    *config.add_atom_matcher() = screenOffMatcher;
-//
-//    auto durationPredicate = CreateScreenIsOnPredicate();
-//    *config.add_predicate() = durationPredicate;
-//
-//    int64_t metricId = 123456;
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(metricId);
-//    durationMetric->set_what(durationPredicate.id());
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-//    const int64_t baseTimeNs = 0; // 0:00
-//    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-//    const int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    // Screen is off at start of bucket.
-//    event = CreateScreenStateChangedEvent(
-//            android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-//    processor->OnLogEvent(event.get());
-//
-//    // Turn screen on.
-//    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-//    processor->OnLogEvent(event.get());
-//
-//    // Turn off screen 30 seconds after turning on.
-//    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-//    processor->OnLogEvent(event.get());
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-//                            ADB_DUMP, FAST, &buffer); // 5:01
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-//    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-//            reports.reports(0).metrics(0).duration_metrics();
-//    EXPECT_EQ(1, durationMetrics.data_size());
-//
-//    auto data = durationMetrics.data(0);
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
-//    EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestTwoBuckets) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-//    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-//    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-//    *config.add_atom_matcher() = screenOnMatcher;
-//    *config.add_atom_matcher() = screenOffMatcher;
-//
-//    auto durationPredicate = CreateScreenIsOnPredicate();
-//    *config.add_predicate() = durationPredicate;
-//
-//    int64_t metricId = 123456;
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(metricId);
-//    durationMetric->set_what(durationPredicate.id());
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-//    const int64_t baseTimeNs = 0; // 0:00
-//    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-//    const int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    // Screen is off at start of bucket.
-//    event = CreateScreenStateChangedEvent(
-//            android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-//    processor->OnLogEvent(event.get());
-//
-//    // Turn screen on.
-//    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-//    processor->OnLogEvent(event.get());
-//
-//    // Turn off screen 30 seconds after turning on.
-//    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-//    processor->OnLogEvent(event.get());
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false, true,
-//                            ADB_DUMP, FAST, &buffer); // 10:01
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-//    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-//            reports.reports(0).metrics(0).duration_metrics();
-//    EXPECT_EQ(1, durationMetrics.data_size());
-//
-//    auto data = durationMetrics.data(0);
-//    EXPECT_EQ(1, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(0, bucketInfo.bucket_num());
-//    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-//    EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivation) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-//    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-//    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-//    auto crashMatcher = CreateProcessCrashAtomMatcher();
-//    *config.add_atom_matcher() = screenOnMatcher;
-//    *config.add_atom_matcher() = screenOffMatcher;
-//    *config.add_atom_matcher() = crashMatcher;
-//
-//    auto durationPredicate = CreateScreenIsOnPredicate();
-//    *config.add_predicate() = durationPredicate;
-//
-//    int64_t metricId = 123456;
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(metricId);
-//    durationMetric->set_what(durationPredicate.id());
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//    auto metric_activation1 = config.add_metric_activation();
-//    metric_activation1->set_metric_id(metricId);
-//    auto event_activation1 = metric_activation1->add_event_activation();
-//    event_activation1->set_atom_matcher_id(crashMatcher.id());
-//    event_activation1->set_ttl_seconds(30); // 30 secs.
-//
-//    const int64_t bucketStartTimeNs = 10000000000;
-//    const int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap.size(), 1u);
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    // Turn screen off.
-//    event = CreateScreenStateChangedEvent(
-//            android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * NS_PER_SEC); // 0:02
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
-//
-//    // Turn screen on.
-//    const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-//    processor.OnLogEvent(event.get(), durationStartNs);
-//
-//    // Activate metric.
-//    const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
-//    const int64_t activationEndNs =
-//            activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
-//    event = CreateAppCrashEvent(111, activationStartNs);
-//    processor.OnLogEvent(event.get(), activationStartNs);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    // Expire activation.
-//    const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
-//    event = CreateScreenBrightnessChangedEvent(64, expirationNs); // 0:47
-//    processor.OnLogEvent(event.get(), expirationNs);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap.size(), 1u);
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    // Turn off screen 10 seconds after activation expiration.
-//    const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-//    processor.OnLogEvent(event.get(),durationEndNs);
-//
-//    // Turn screen on.
-//    const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-//    processor.OnLogEvent(event.get(), duration2StartNs);
-//
-//    // Turn off screen.
-//    const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, duration2EndNs);
-//    processor.OnLogEvent(event.get(), duration2EndNs);
-//
-//    // Activate metric.
-//    const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
-//    const int64_t activation2EndNs =
-//            activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
-//    event = CreateAppCrashEvent(211, activation2StartNs);
-//    processor.OnLogEvent(event.get(), activation2StartNs);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-//                            ADB_DUMP, FAST, &buffer); // 5:01
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-//    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-//    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-//            reports.reports(0).metrics(0).duration_metrics();
-//    EXPECT_EQ(1, durationMetrics.data_size());
-//
-//    auto data = durationMetrics.data(0);
-//    EXPECT_EQ(1, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(0, bucketInfo.bucket_num());
-//    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithCondition) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-//    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-//    *config.add_predicate() = holdingWakelockPredicate;
-//
-//    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-//    *config.add_predicate() = isInBackgroundPredicate;
-//
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(StringToId("WakelockDuration"));
-//    durationMetric->set_what(holdingWakelockPredicate.id());
-//    durationMetric->set_condition(isInBackgroundPredicate.id());
-//    durationMetric->set_aggregation_type(DurationMetric::SUM);
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//
-//    ConfigKey cfgKey;
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_TRUE(eventActivationMap.empty());
-//
-//    int appUid = 123;
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-//    auto event = CreateAcquireWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateMoveToForegroundEvent(
-//            appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateReleaseWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + 4 * 60 * NS_PER_SEC); // 4:00
-//    processor->OnLogEvent(event.get());
-//
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//
-//    // Validate bucket info.
-//    EXPECT_EQ(1, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-//    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-//    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-//    // The predicate is dimensioning by first attribution node by uid.
-//    FieldMatcher dimensions = CreateAttributionUidDimensions(
-//            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-//    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-//    *config.add_predicate() = holdingWakelockPredicate;
-//
-//    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-//    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-//        CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-//    *config.add_predicate() = isInBackgroundPredicate;
-//
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(StringToId("WakelockDuration"));
-//    durationMetric->set_what(holdingWakelockPredicate.id());
-//    durationMetric->set_condition(isInBackgroundPredicate.id());
-//    durationMetric->set_aggregation_type(DurationMetric::SUM);
-//    // The metric is dimensioning by first attribution node and only by uid.
-//    *durationMetric->mutable_dimensions_in_what() =
-//        CreateAttributionUidDimensions(
-//            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//
-//    // Links between wakelock state atom and condition of app is in background.
-//    auto links = durationMetric->add_links();
-//    links->set_condition(isInBackgroundPredicate.id());
-//    auto dimensionWhat = links->mutable_fields_in_what();
-//    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-//    dimensionWhat->add_child()->set_field(1);  // uid field.
-//    *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-//            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-//    ConfigKey cfgKey;
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_TRUE(eventActivationMap.empty());
-//
-//    int appUid = 123;
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-//    auto event = CreateAcquireWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateReleaseWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + 60 * NS_PER_SEC); // 1:00
-//    processor->OnLogEvent(event.get());
-//
-//
-//    event = CreateMoveToForegroundEvent(
-//            appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-//    processor->OnLogEvent(event.get());
-//
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // Validate dimension value.
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
-//    // Validate bucket info.
-//    EXPECT_EQ(1, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
-//    StatsdConfig config;
-//    config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-//    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-//    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//    *config.add_atom_matcher() = screenOnMatcher;
-//
-//    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-//    // The predicate is dimensioning by first attribution node by uid.
-//    FieldMatcher dimensions = CreateAttributionUidDimensions(
-//            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-//    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-//    *config.add_predicate() = holdingWakelockPredicate;
-//
-//    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-//    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-//        CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-//    *config.add_predicate() = isInBackgroundPredicate;
-//
-//    auto durationMetric = config.add_duration_metric();
-//    durationMetric->set_id(StringToId("WakelockDuration"));
-//    durationMetric->set_what(holdingWakelockPredicate.id());
-//    durationMetric->set_condition(isInBackgroundPredicate.id());
-//    durationMetric->set_aggregation_type(DurationMetric::SUM);
-//    // The metric is dimensioning by first attribution node and only by uid.
-//    *durationMetric->mutable_dimensions_in_what() =
-//        CreateAttributionUidDimensions(
-//            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-//    durationMetric->set_bucket(FIVE_MINUTES);
-//
-//    // Links between wakelock state atom and condition of app is in background.
-//    auto links = durationMetric->add_links();
-//    links->set_condition(isInBackgroundPredicate.id());
-//    auto dimensionWhat = links->mutable_fields_in_what();
-//    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-//    dimensionWhat->add_child()->set_field(1);  // uid field.
-//    *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-//            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-//    auto metric_activation1 = config.add_metric_activation();
-//    metric_activation1->set_metric_id(durationMetric->id());
-//    auto event_activation1 = metric_activation1->add_event_activation();
-//    event_activation1->set_atom_matcher_id(screenOnMatcher.id());
-//    event_activation1->set_ttl_seconds(60 * 2);  // 2 minutes.
-//
-//    ConfigKey cfgKey;
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap.size(), 1u);
-//    EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    int appUid = 123;
-//    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-//    auto event = CreateAcquireWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-//    processor->OnLogEvent(event.get());
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-//    processor->OnLogEvent(event.get());
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    const int64_t durationEndNs =
-//            durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
-//    event = CreateAppCrashEvent(333, durationEndNs);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    event = CreateMoveToForegroundEvent(
-//            appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateReleaseWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC); // 4:17
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateMoveToBackgroundEvent(
-//            appUid, bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC); // 4:20
-//    processor->OnLogEvent(event.get());
-//
-//    event = CreateAcquireWakelockEvent(
-//            attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC); // 4:25
-//    processor->OnLogEvent(event.get());
-//
-//    const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-//    processor->OnLogEvent(event.get());
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
-//    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_GT(buffer.size(), 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // Validate dimension value.
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
-//    // Validate bucket info.
-//    EXPECT_EQ(2, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-//
-//    bucketInfo = data.bucket_info(1);
-//    EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
-//}
+TEST(DurationMetricE2eTest, TestOneBucket) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+    *config.add_atom_matcher() = screenOnMatcher;
+    *config.add_atom_matcher() = screenOffMatcher;
+
+    auto durationPredicate = CreateScreenIsOnPredicate();
+    *config.add_predicate() = durationPredicate;
+
+    int64_t metricId = 123456;
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(metricId);
+    durationMetric->set_what(durationPredicate.id());
+    durationMetric->set_bucket(FIVE_MINUTES);
+    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    const int64_t baseTimeNs = 0;                                   // 0:00
+    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
+    const int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+
+    std::unique_ptr<LogEvent> event;
+
+    // Screen is off at start of bucket.
+    event = CreateScreenStateChangedEvent(configAddedTimeNs,
+                                          android::view::DISPLAY_STATE_OFF);  // 0:01
+    processor->OnLogEvent(event.get());
+
+    // Turn screen on.
+    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC;  // 0:11
+    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(event.get());
+
+    // Turn off screen 30 seconds after turning on.
+    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC;  // 0:41
+    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(event.get());
+
+    event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64);  // 0:42
+    processor->OnLogEvent(event.get());
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+                            ADB_DUMP, FAST, &buffer);  // 5:01
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+            reports.reports(0).metrics(0).duration_metrics();
+    EXPECT_EQ(1, durationMetrics.data_size());
+
+    auto data = durationMetrics.data(0);
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
+    EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestTwoBuckets) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+    *config.add_atom_matcher() = screenOnMatcher;
+    *config.add_atom_matcher() = screenOffMatcher;
+
+    auto durationPredicate = CreateScreenIsOnPredicate();
+    *config.add_predicate() = durationPredicate;
+
+    int64_t metricId = 123456;
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(metricId);
+    durationMetric->set_what(durationPredicate.id());
+    durationMetric->set_bucket(FIVE_MINUTES);
+    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    const int64_t baseTimeNs = 0;                                   // 0:00
+    const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC;  // 0:01
+    const int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+
+    std::unique_ptr<LogEvent> event;
+
+    // Screen is off at start of bucket.
+    event = CreateScreenStateChangedEvent(configAddedTimeNs,
+                                          android::view::DISPLAY_STATE_OFF);  // 0:01
+    processor->OnLogEvent(event.get());
+
+    // Turn screen on.
+    const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC;  // 0:11
+    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(event.get());
+
+    // Turn off screen 30 seconds after turning on.
+    const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC;  // 0:41
+    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(event.get());
+
+    event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64);  // 0:42
+    processor->OnLogEvent(event.get());
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false,
+                            true, ADB_DUMP, FAST, &buffer);  // 10:01
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+            reports.reports(0).metrics(0).duration_metrics();
+    EXPECT_EQ(1, durationMetrics.data_size());
+
+    auto data = durationMetrics.data(0);
+    EXPECT_EQ(1, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(0, bucketInfo.bucket_num());
+    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+    EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivation) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+    auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+    auto crashMatcher = CreateProcessCrashAtomMatcher();
+    *config.add_atom_matcher() = screenOnMatcher;
+    *config.add_atom_matcher() = screenOffMatcher;
+    *config.add_atom_matcher() = crashMatcher;
+
+    auto durationPredicate = CreateScreenIsOnPredicate();
+    *config.add_predicate() = durationPredicate;
+
+    int64_t metricId = 123456;
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(metricId);
+    durationMetric->set_what(durationPredicate.id());
+    durationMetric->set_bucket(FIVE_MINUTES);
+    durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    auto metric_activation1 = config.add_metric_activation();
+    metric_activation1->set_metric_id(metricId);
+    auto event_activation1 = metric_activation1->add_event_activation();
+    event_activation1->set_atom_matcher_id(crashMatcher.id());
+    event_activation1->set_ttl_seconds(30);  // 30 secs.
+
+    const int64_t bucketStartTimeNs = 10000000000;
+    const int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);  // 0:00
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap.size(), 1u);
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    std::unique_ptr<LogEvent> event;
+
+    // Turn screen off.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC,
+                                          android::view::DISPLAY_STATE_OFF);  // 0:02
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
+
+    // Turn screen on.
+    const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC;  // 0:05
+    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), durationStartNs);
+
+    // Activate metric.
+    const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC;  // 0:10
+    const int64_t activationEndNs =
+            activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC;  // 0:40
+    event = CreateAppCrashEvent(activationStartNs, 111);
+    processor.OnLogEvent(event.get(), activationStartNs);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    // Expire activation.
+    const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
+    event = CreateScreenBrightnessChangedEvent(expirationNs, 64);  // 0:47
+    processor.OnLogEvent(event.get(), expirationNs);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap.size(), 1u);
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    // Turn off screen 10 seconds after activation expiration.
+    const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC;  // 0:50
+    event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+    processor.OnLogEvent(event.get(), durationEndNs);
+
+    // Turn screen on.
+    const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC;  // 0:55
+    event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), duration2StartNs);
+
+    // Turn off screen.
+    const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC;  // 1:05
+    event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
+    processor.OnLogEvent(event.get(), duration2EndNs);
+
+    // Activate metric.
+    const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC;  // 1:10
+    const int64_t activation2EndNs =
+            activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC;  // 1:40
+    event = CreateAppCrashEvent(activation2StartNs, 211);
+    processor.OnLogEvent(event.get(), activation2StartNs);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+                           ADB_DUMP, FAST, &buffer);  // 5:01
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+    EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+    const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+            reports.reports(0).metrics(0).duration_metrics();
+    EXPECT_EQ(1, durationMetrics.data_size());
+
+    auto data = durationMetrics.data(0);
+    EXPECT_EQ(1, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(0, bucketInfo.bucket_num());
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithCondition) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+    *config.add_predicate() = holdingWakelockPredicate;
+
+    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+    *config.add_predicate() = isInBackgroundPredicate;
+
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(StringToId("WakelockDuration"));
+    durationMetric->set_what(holdingWakelockPredicate.id());
+    durationMetric->set_condition(isInBackgroundPredicate.id());
+    durationMetric->set_aggregation_type(DurationMetric::SUM);
+    durationMetric->set_bucket(FIVE_MINUTES);
+
+    ConfigKey cfgKey;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_TRUE(eventActivationMap.empty());
+
+    int appUid = 123;
+    vector<int> attributionUids1 = {appUid};
+    vector<string> attributionTags1 = {"App1"};
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+                                            attributionTags1,
+                                            "wl1");  // 0:10
+    processor->OnLogEvent(event.get());
+
+    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
+    processor->OnLogEvent(event.get());
+
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+                                        appUid);  // 3:15
+    processor->OnLogEvent(event.get());
+
+    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC, attributionUids1,
+                                       attributionTags1,
+                                       "wl1");  // 4:00
+    processor->OnLogEvent(event.get());
+
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+
+    // Validate bucket info.
+    EXPECT_EQ(1, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+    // The predicate is dimensioning by first attribution node by uid.
+    FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+                                                             {Position::FIRST});
+    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+    *config.add_predicate() = holdingWakelockPredicate;
+
+    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+            CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+    *config.add_predicate() = isInBackgroundPredicate;
+
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(StringToId("WakelockDuration"));
+    durationMetric->set_what(holdingWakelockPredicate.id());
+    durationMetric->set_condition(isInBackgroundPredicate.id());
+    durationMetric->set_aggregation_type(DurationMetric::SUM);
+    // The metric is dimensioning by first attribution node and only by uid.
+    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+    durationMetric->set_bucket(FIVE_MINUTES);
+
+    // Links between wakelock state atom and condition of app is in background.
+    auto links = durationMetric->add_links();
+    links->set_condition(isInBackgroundPredicate.id());
+    auto dimensionWhat = links->mutable_fields_in_what();
+    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+    dimensionWhat->add_child()->set_field(1);  // uid field.
+    *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+    ConfigKey cfgKey;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_TRUE(eventActivationMap.empty());
+
+    int appUid = 123;
+    std::vector<int> attributionUids1 = {appUid};
+    std::vector<string> attributionTags1 = {"App1"};
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+                                            attributionTags1, "wl1");  // 0:10
+    processor->OnLogEvent(event.get());
+
+    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
+    processor->OnLogEvent(event.get());
+
+    event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+                                       attributionTags1, "wl1");  // 1:00
+    processor->OnLogEvent(event.get());
+
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+                                        appUid);  // 3:15
+    processor->OnLogEvent(event.get());
+
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
+    // Validate bucket info.
+    EXPECT_EQ(1, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+    *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+    *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+    *config.add_atom_matcher() = screenOnMatcher;
+
+    auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+    // The predicate is dimensioning by first attribution node by uid.
+    FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+                                                             {Position::FIRST});
+    *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+    *config.add_predicate() = holdingWakelockPredicate;
+
+    auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+    *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+            CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+    *config.add_predicate() = isInBackgroundPredicate;
+
+    auto durationMetric = config.add_duration_metric();
+    durationMetric->set_id(StringToId("WakelockDuration"));
+    durationMetric->set_what(holdingWakelockPredicate.id());
+    durationMetric->set_condition(isInBackgroundPredicate.id());
+    durationMetric->set_aggregation_type(DurationMetric::SUM);
+    // The metric is dimensioning by first attribution node and only by uid.
+    *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+    durationMetric->set_bucket(FIVE_MINUTES);
+
+    // Links between wakelock state atom and condition of app is in background.
+    auto links = durationMetric->add_links();
+    links->set_condition(isInBackgroundPredicate.id());
+    auto dimensionWhat = links->mutable_fields_in_what();
+    dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+    dimensionWhat->add_child()->set_field(1);  // uid field.
+    *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+            android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+    auto metric_activation1 = config.add_metric_activation();
+    metric_activation1->set_metric_id(durationMetric->id());
+    auto event_activation1 = metric_activation1->add_event_activation();
+    event_activation1->set_atom_matcher_id(screenOnMatcher.id());
+    event_activation1->set_ttl_seconds(60 * 2);  // 2 minutes.
+
+    ConfigKey cfgKey;
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap.size(), 1u);
+    EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    int appUid = 123;
+    std::vector<int> attributionUids1 = {appUid};
+    std::vector<string> attributionTags1 = {"App1"};
+
+    auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+                                            attributionTags1, "wl1");  // 0:10
+    processor->OnLogEvent(event.get());
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid);  // 0:22
+    processor->OnLogEvent(event.get());
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC;  // 0:30
+    event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(event.get());
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    const int64_t durationEndNs =
+            durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC;  // 3:00
+    event = CreateAppCrashEvent(durationEndNs, 333);
+    processor->OnLogEvent(event.get());
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+                                        appUid);  // 3:15
+    processor->OnLogEvent(event.get());
+
+    event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC,
+                                       attributionUids1, attributionTags1, "wl1");  // 4:17
+    processor->OnLogEvent(event.get());
+
+    event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC,
+                                        appUid);  // 4:20
+    processor->OnLogEvent(event.get());
+
+    event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC,
+                                       attributionUids1, attributionTags1, "wl1");  // 4:25
+    processor->OnLogEvent(event.get());
+
+    const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC;  // 4:30
+    event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(event.get());
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
+    EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_GT(buffer.size(), 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, appUid);
+    // Validate bucket info.
+    EXPECT_EQ(2, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+
+    bucketInfo = data.bucket_info(1);
+    EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 7f651d4..594c1e6 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -65,482 +65,465 @@
 
 }  // namespaces
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
-//    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             ATOM_TAG);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//
-//    // When creating the config, the gauge metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& nextPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-//    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                        configAddedTimeNs + 55);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-//    processor->informPullAlarmFired(nextPullTimeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-//
-//    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + bucketSizeNs + 10);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + bucketSizeNs + 100);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-//              nextPullTimeNs);
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-//    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                  configAddedTimeNs + 3 * bucketSizeNs + 2);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 3);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                  configAddedTimeNs + 5 * bucketSizeNs + 1);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 2);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-//    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-//    auto data = gaugeMetrics.data(0);
-//    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    EXPECT_EQ(6, data.bucket_info_size());
-//
-//    EXPECT_EQ(1, data.bucket_info(0).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(1).atom_size());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
-//              data.bucket_info(1).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(2).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1,
-//              data.bucket_info(2).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(3).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1,
-//              data.bucket_info(3).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(4).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-//              data.bucket_info(4).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(5).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2,
-//              data.bucket_info(5).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
-//    auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             ATOM_TAG);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//
-//    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                        configAddedTimeNs + 55);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + bucketSizeNs + 10);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + bucketSizeNs + 100);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                  configAddedTimeNs + 3 * bucketSizeNs + 2);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                  configAddedTimeNs + 5 * bucketSizeNs + 1);
-//    processor->OnLogEvent(screenOffEvent.get());
-//    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                  configAddedTimeNs + 5 * bucketSizeNs + 3);
-//    processor->OnLogEvent(screenOnEvent.get());
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                  configAddedTimeNs + 5 * bucketSizeNs + 10);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-//    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-//    auto data = gaugeMetrics.data(0);
-//    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    EXPECT_EQ(3, data.bucket_info_size());
-//
-//    EXPECT_EQ(1, data.bucket_info(0).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(1).atom_size());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100,
-//              data.bucket_info(1).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(2, data.bucket_info(2).atom_size());
-//    EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-//              data.bucket_info(2).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10,
-//              data.bucket_info(2).elapsed_timestamp_nanos(1));
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//    EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
-//    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             ATOM_TAG);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//
-//    // When creating the config, the gauge metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& nextPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-//    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                        configAddedTimeNs + 55);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + bucketSizeNs + 10);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    // Pulling alarm arrives one bucket size late.
-//    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + 3 * bucketSizeNs + 11);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    // Pulling alarm arrives more than one bucket size late.
-//    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-//    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-//    auto data = gaugeMetrics.data(0);
-//    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    EXPECT_EQ(3, data.bucket_info_size());
-//
-//    EXPECT_EQ(1, data.bucket_info(0).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(1).atom_size());
-//    EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
-//              data.bucket_info(1).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    EXPECT_EQ(1, data.bucket_info(2).atom_size());
-//    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12,
-//              data.bucket_info(2).elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
-//    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
-//
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-//    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-//    *config.add_atom_matcher() = batterySaverStartMatcher;
-//    const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-//    auto metric_activation = config.add_metric_activation();
-//    metric_activation->set_metric_id(metricId);
-//    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-//    auto event_activation = metric_activation->add_event_activation();
-//    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-//    event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             ATOM_TAG);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // When creating the config, the gauge metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& nextPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-//    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-//    // Event should not be kept.
-//    processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // Activate the metric. A pull occurs upon activation.
-//    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-//    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-//    processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // This event should be kept. 2 total.
-//    processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-//              nextPullTimeNs);
-//
-//    // This event should be kept. 3 total.
-//    processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-//    // Create random event to deactivate metric.
-//    auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-//    processor->OnLogEvent(deactivationEvent.get());
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // Event should not be kept. 3 total.
-//    processor->informPullAlarmFired(nextPullTimeNs + 3);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-//    processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-//    EXPECT_GT((int)gaugeMetrics.data_size(), 0);
-//
-//    auto data = gaugeMetrics.data(0);
-//    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    EXPECT_EQ(3, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(1, bucketInfo.atom_size());
-//    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    bucketInfo = data.bucket_info(1);
-//    EXPECT_EQ(1, bucketInfo.atom_size());
-//    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-//    bucketInfo = data.bucket_info(2);
-//    EXPECT_EQ(1, bucketInfo.atom_size());
-//    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
-//    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-//    EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
-//            bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
-//            bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-//    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
+    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor =
+            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& nextPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+    auto screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+                                                       android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+    processor->informPullAlarmFired(nextPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+                                                  android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 3);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(nextPullTimeNs + 2);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
+
+    processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(6, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(2).atom_size());
+    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(3).atom_size());
+    EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(4).atom_size());
+    EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(5).atom_size());
+    EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
+    auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor =
+            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    auto screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+                                                       android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+                                                  android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 3,
+                                                  android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 10,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(2, data.bucket_info(2).atom_size());
+    EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1));
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+    EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
+    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor =
+            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& nextPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+    auto screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+                                                       android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    // Pulling alarm arrives one bucket size late.
+    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 11,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives more than one bucket size late.
+    processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(1, data.bucket_info(0).atom_size());
+    EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(1).atom_size());
+    EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
+              data.bucket_info(1).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    EXPECT_EQ(1, data.bucket_info(2).atom_size());
+    EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0));
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
+    auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
+
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+    *config.add_atom_matcher() = batterySaverStartMatcher;
+    const int64_t ttlNs = 2 * bucketSizeNs;  // Two buckets.
+    auto metric_activation = config.add_metric_activation();
+    metric_activation->set_metric_id(metricId);
+    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+    auto event_activation = metric_activation->add_event_activation();
+    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+    event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+    ConfigKey cfgKey;
+    auto processor =
+            CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                    SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // When creating the config, the gauge metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& nextPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    // Event should not be kept.
+    processor->informPullAlarmFired(nextPullTimeNs + 1);  // 15 mins + 1 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // Activate the metric. A pull occurs upon activation.
+    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000);  // 2 millis.
+    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+    processor->OnLogEvent(batterySaverOnEvent.get());  // 15 mins + 2 ms.
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // This event should be kept. 2 total.
+    processor->informPullAlarmFired(nextPullTimeNs + 1);  // 20 mins + 1 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+    // This event should be kept. 3 total.
+    processor->informPullAlarmFired(nextPullTimeNs + 2);  // 25 mins + 2 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+    // Create random event to deactivate metric.
+    auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+    processor->OnLogEvent(deactivationEvent.get());
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // Event should not be kept. 3 total.
+    processor->informPullAlarmFired(nextPullTimeNs + 3);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+    processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+    EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+
+    auto data = gaugeMetrics.data(0);
+    EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(1, bucketInfo.atom_size());
+    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+    EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
+    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    bucketInfo = data.bucket_info(1);
+    EXPECT_EQ(1, bucketInfo.atom_size());
+    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
+    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+    bucketInfo = data.bucket_info(2);
+    EXPECT_EQ(1, bucketInfo.atom_size());
+    EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
+    EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+    EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
+              bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
+              bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+    EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+}
 
 TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
     auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index ef6e753..6e3d93a 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -14,12 +14,13 @@
 
 #include <gtest/gtest.h>
 
+#include <vector>
+
 #include "src/StatsLogProcessor.h"
 #include "src/stats_log_util.h"
+#include "stats_event.h"
 #include "tests/statsd_test_util.h"
 
-#include <vector>
-
 namespace android {
 namespace os {
 namespace statsd {
@@ -68,221 +69,227 @@
     return config;
 }
 
-// TODO(b/149590301): Update this helper to use new socket schema.
-//std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
-//    const int uid, const string& pkg_name, AppStartOccurred::TransitionType type,
-//    const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
-//    int64_t activity_start_msec, uint64_t timestampNs) {
-//    auto logEvent = std::make_unique<LogEvent>(
-//        android::util::APP_START_OCCURRED, timestampNs);
-//    logEvent->write(uid);
-//    logEvent->write(pkg_name);
-//    logEvent->write(type);
-//    logEvent->write(activity_name);
-//    logEvent->write(calling_pkg_name);
-//    logEvent->write(is_instant_app);
-//    logEvent->write(activity_start_msec);
-//    logEvent->init();
-//    return logEvent;
-//}
+std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
+        uint64_t timestampNs, const int uid, const string& pkg_name,
+        AppStartOccurred::TransitionType type, const string& activity_name,
+        const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::APP_START_OCCURRED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    AStatsEvent_writeString(statsEvent, pkg_name.c_str());
+    AStatsEvent_writeInt32(statsEvent, type);
+    AStatsEvent_writeString(statsEvent, activity_name.c_str());
+    AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str());
+    AStatsEvent_writeInt32(statsEvent, is_instant_app);
+    AStatsEvent_writeInt32(statsEvent, activity_start_msec);
+    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;
+}
 
 }  // namespace
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
-//    for (const auto& sampling_type :
-//            { GaugeMetric::FIRST_N_SAMPLES, GaugeMetric:: RANDOM_ONE_SAMPLE }) {
-//        auto config = CreateStatsdConfigForPushedEvent(sampling_type);
-//        int64_t bucketStartTimeNs = 10000000000;
-//        int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-//        ConfigKey cfgKey;
-//        auto processor = CreateStatsLogProcessor(
-//                bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//        EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//        EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//        int appUid1 = 123;
-//        int appUid2 = 456;
-//        std::vector<std::unique_ptr<LogEvent>> events;
-//        events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
-//        events.push_back(CreateMoveToForegroundEvent(
-//                appUid1, bucketStartTimeNs + bucketSizeNs + 250));
-//        events.push_back(CreateMoveToBackgroundEvent(
-//                appUid1, bucketStartTimeNs + bucketSizeNs + 350));
-//        events.push_back(CreateMoveToForegroundEvent(
-//            appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//
-//
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::WARM, "activity_name1", "calling_pkg_name1",
-//            true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::HOT, "activity_name2", "calling_pkg_name2",
-//            true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::COLD, "activity_name3", "calling_pkg_name3",
-//            true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::WARM, "activity_name4", "calling_pkg_name4",
-//            true /*is_instant_app*/, 104 /*activity_start_msec*/,
-//            bucketStartTimeNs + bucketSizeNs + 30));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::COLD, "activity_name5", "calling_pkg_name5",
-//            true /*is_instant_app*/, 105 /*activity_start_msec*/,
-//            bucketStartTimeNs + 2 * bucketSizeNs));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid1, "app1", AppStartOccurred::HOT, "activity_name6", "calling_pkg_name6",
-//            false /*is_instant_app*/, 106 /*activity_start_msec*/,
-//            bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-//        events.push_back(CreateMoveToBackgroundEvent(
-//                appUid2, bucketStartTimeNs + bucketSizeNs + 10));
-//        events.push_back(CreateAppStartOccurredEvent(
-//            appUid2, "app2", AppStartOccurred::COLD, "activity_name7", "calling_pkg_name7",
-//            true /*is_instant_app*/, 201 /*activity_start_msec*/,
-//            bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-//        sortLogEventsByTimestamp(&events);
-//
-//        for (const auto& event : events) {
-//            processor->OnLogEvent(event.get());
-//        }
-//        ConfigMetricsReportList reports;
-//        vector<uint8_t> buffer;
-//        processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
-//                                ADB_DUMP, FAST, &buffer);
-//        EXPECT_TRUE(buffer.size() > 0);
-//        EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//        backfillDimensionPath(&reports);
-//        backfillStringInReport(&reports);
-//        backfillStartEndTimestamp(&reports);
-//        EXPECT_EQ(1, reports.reports_size());
-//        EXPECT_EQ(1, reports.reports(0).metrics_size());
-//        StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-//        sortMetricDataByDimensionsValue(
-//                reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-//        EXPECT_EQ(2, gaugeMetrics.data_size());
-//
-//        auto data = gaugeMetrics.data(0);
-//        EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
-//        EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//        EXPECT_EQ(1 /* uid field */,
-//                  data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//        EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//        EXPECT_EQ(3, data.bucket_info_size());
-//        if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
-//            EXPECT_EQ(2, data.bucket_info(0).atom_size());
-//            EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//                      data.bucket_info(0).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::HOT,
-//                      data.bucket_info(0).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name2",
-//                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(102L,
-//                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-//            EXPECT_EQ(AppStartOccurred::COLD,
-//                      data.bucket_info(0).atom(1).app_start_occurred().type());
-//            EXPECT_EQ("activity_name3",
-//                      data.bucket_info(0).atom(1).app_start_occurred().activity_name());
-//            EXPECT_EQ(103L,
-//                      data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
-//
-//            EXPECT_EQ(1, data.bucket_info(1).atom_size());
-//            EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//                      data.bucket_info(1).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//                      data.bucket_info(1).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::WARM,
-//                      data.bucket_info(1).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name4",
-//                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(104L,
-//                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-//            EXPECT_EQ(2, data.bucket_info(2).atom_size());
-//            EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//                      data.bucket_info(2).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//                      data.bucket_info(2).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::COLD,
-//                      data.bucket_info(2).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name5",
-//                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(105L,
-//                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-//            EXPECT_EQ(AppStartOccurred::HOT,
-//                      data.bucket_info(2).atom(1).app_start_occurred().type());
-//            EXPECT_EQ("activity_name6",
-//                      data.bucket_info(2).atom(1).app_start_occurred().activity_name());
-//            EXPECT_EQ(106L,
-//                      data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
-//        } else {
-//            EXPECT_EQ(1, data.bucket_info(0).atom_size());
-//            EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//                      data.bucket_info(0).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::HOT,
-//                      data.bucket_info(0).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name2",
-//                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(102L,
-//                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-//
-//            EXPECT_EQ(1, data.bucket_info(1).atom_size());
-//            EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//                      data.bucket_info(1).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//                      data.bucket_info(1).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::WARM,
-//                      data.bucket_info(1).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name4",
-//                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(104L,
-//                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-//            EXPECT_EQ(1, data.bucket_info(2).atom_size());
-//            EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-//            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//                      data.bucket_info(2).start_bucket_elapsed_nanos());
-//            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//                      data.bucket_info(2).end_bucket_elapsed_nanos());
-//            EXPECT_EQ(AppStartOccurred::COLD,
-//                      data.bucket_info(2).atom(0).app_start_occurred().type());
-//            EXPECT_EQ("activity_name5",
-//                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-//            EXPECT_EQ(105L,
-//                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-//        }
-//
-//        data = gaugeMetrics.data(1);
-//
-//        EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
-//        EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-//        EXPECT_EQ(1 /* uid field */,
-//                  data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//        EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//        EXPECT_EQ(1, data.bucket_info_size());
-//        EXPECT_EQ(1, data.bucket_info(0).atom_size());
-//        EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-//        EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//                  data.bucket_info(0).start_bucket_elapsed_nanos());
-//        EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//                  data.bucket_info(0).end_bucket_elapsed_nanos());
-//        EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
-//        EXPECT_EQ("activity_name7",
-//                  data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-//        EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-//    }
-//}
+TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
+    for (const auto& sampling_type :
+         {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
+        auto config = CreateStatsdConfigForPushedEvent(sampling_type);
+        int64_t bucketStartTimeNs = 10000000000;
+        int64_t bucketSizeNs =
+                TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+        ConfigKey cfgKey;
+        auto processor =
+                CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+        EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+        EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+        int appUid1 = 123;
+        int appUid2 = 456;
+        std::vector<std::unique_ptr<LogEvent>> events;
+        events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
+        events.push_back(
+                CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
+        events.push_back(
+                CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
+        events.push_back(
+                CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
+
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
+                "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
+                "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
+                "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
+                "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
+                104 /*activity_start_msec*/));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
+                "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
+                105 /*activity_start_msec*/));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
+                "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
+                106 /*activity_start_msec*/));
+
+        events.push_back(
+                CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
+        events.push_back(CreateAppStartOccurredEvent(
+                bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
+                "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
+                201 /*activity_start_msec*/));
+
+        sortLogEventsByTimestamp(&events);
+
+        for (const auto& event : events) {
+            processor->OnLogEvent(event.get());
+        }
+        ConfigMetricsReportList reports;
+        vector<uint8_t> buffer;
+        processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
+                                FAST, &buffer);
+        EXPECT_TRUE(buffer.size() > 0);
+        EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+        backfillDimensionPath(&reports);
+        backfillStringInReport(&reports);
+        backfillStartEndTimestamp(&reports);
+        EXPECT_EQ(1, reports.reports_size());
+        EXPECT_EQ(1, reports.reports(0).metrics_size());
+        StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+        sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
+                                        &gaugeMetrics);
+        EXPECT_EQ(2, gaugeMetrics.data_size());
+
+        auto data = gaugeMetrics.data(0);
+        EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
+        EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+        EXPECT_EQ(1 /* uid field */,
+                  data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+        EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+        EXPECT_EQ(3, data.bucket_info_size());
+        if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
+            EXPECT_EQ(2, data.bucket_info(0).atom_size());
+            EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(0).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::HOT,
+                      data.bucket_info(0).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name2",
+                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(102L,
+                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+            EXPECT_EQ(AppStartOccurred::COLD,
+                      data.bucket_info(0).atom(1).app_start_occurred().type());
+            EXPECT_EQ("activity_name3",
+                      data.bucket_info(0).atom(1).app_start_occurred().activity_name());
+            EXPECT_EQ(103L,
+                      data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
+
+            EXPECT_EQ(1, data.bucket_info(1).atom_size());
+            EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(1).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(1).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::WARM,
+                      data.bucket_info(1).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name4",
+                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(104L,
+                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+            EXPECT_EQ(2, data.bucket_info(2).atom_size());
+            EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(2).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+                      data.bucket_info(2).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::COLD,
+                      data.bucket_info(2).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name5",
+                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(105L,
+                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+            EXPECT_EQ(AppStartOccurred::HOT,
+                      data.bucket_info(2).atom(1).app_start_occurred().type());
+            EXPECT_EQ("activity_name6",
+                      data.bucket_info(2).atom(1).app_start_occurred().activity_name());
+            EXPECT_EQ(106L,
+                      data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
+        } else {
+            EXPECT_EQ(1, data.bucket_info(0).atom_size());
+            EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(0).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::HOT,
+                      data.bucket_info(0).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name2",
+                      data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(102L,
+                      data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+
+            EXPECT_EQ(1, data.bucket_info(1).atom_size());
+            EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+                      data.bucket_info(1).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(1).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::WARM,
+                      data.bucket_info(1).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name4",
+                      data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(104L,
+                      data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+            EXPECT_EQ(1, data.bucket_info(2).atom_size());
+            EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+            EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                      data.bucket_info(2).start_bucket_elapsed_nanos());
+            EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+                      data.bucket_info(2).end_bucket_elapsed_nanos());
+            EXPECT_EQ(AppStartOccurred::COLD,
+                      data.bucket_info(2).atom(0).app_start_occurred().type());
+            EXPECT_EQ("activity_name5",
+                      data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+            EXPECT_EQ(105L,
+                      data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+        }
+
+        data = gaugeMetrics.data(1);
+
+        EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
+        EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+        EXPECT_EQ(1 /* uid field */,
+                  data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+        EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+        EXPECT_EQ(1, data.bucket_info_size());
+        EXPECT_EQ(1, data.bucket_info(0).atom_size());
+        EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+        EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+                  data.bucket_info(0).start_bucket_elapsed_nanos());
+        EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+                  data.bucket_info(0).end_bucket_elapsed_nanos());
+        EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
+        EXPECT_EQ("activity_name7",
+                  data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+        EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+    }
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index f3f7df77..1dd90e2 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -233,1609 +233,1602 @@
 
 }  // namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(MetricActivationE2eTest, TestCountMetric) {
-//    auto config = CreateStatsdConfig();
-//
-//    int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-//    int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    long timeBase1 = 1;
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-//    // triggered by screen on event (tracker index 2).
-//    EXPECT_EQ(eventActivationMap.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 0);
-//
-//    // Activated by battery save mode.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-//    // First processed event.
-//    event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-//    // Activated by screen on event.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 20);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-//    // 2nd processed event.
-//    // The activation by screen_on event expires, but the one by battery save mode is still active.
-//    event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    // No new broadcast since the config should still be active.
-//    EXPECT_EQ(broadcastCount, 1);
-//
-//    // 3rd processed event.
-//    event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-//    // All activations expired.
-//    event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-//    // Re-activate metric via screen on.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-//    // 4th processed event.
-//    event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(4, countMetrics.data_size());
-//
-//    auto data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
-//    auto config = CreateStatsdConfigWithOneDeactivation();
-//
-//    int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-//    int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    long timeBase1 = 1;
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-//    // triggered by screen on event (tracker index 2).
-//    EXPECT_EQ(eventActivationMap.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap.size(), 1u);
-//    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-//    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 0);
-//
-//    // Activated by battery save mode.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // First processed event.
-//    event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-//    // Activated by screen on event.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 20);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // 2nd processed event.
-//    // The activation by screen_on event expires, but the one by battery save mode is still active.
-//    event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    // No new broadcast since the config should still be active.
-//    EXPECT_EQ(broadcastCount, 1);
-//
-//    // 3rd processed event.
-//    event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-//    // All activations expired.
-//    event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // Re-activate metric via screen on.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // 4th processed event.
-//    event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // 5th processed event.
-//    event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-//    // Cancel battery saver mode activation.
-//    event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // Screen-on activation expired.
-//    event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 5);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    // Cancel battery saver mode activation.
-//    event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 6);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(5, countMetrics.data_size());
-//
-//    auto data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(4);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
-//    auto config = CreateStatsdConfigWithTwoDeactivations();
-//
-//    int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-//    int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    long timeBase1 = 1;
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-//    // triggered by screen on event (tracker index 2).
-//    EXPECT_EQ(eventActivationMap.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap.size(), 2u);
-//    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-//    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-//    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 0);
-//
-//    // Activated by battery save mode.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // First processed event.
-//    event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-//    // Activated by screen on event.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 20);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // 2nd processed event.
-//    // The activation by screen_on event expires, but the one by battery save mode is still active.
-//    event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    // No new broadcast since the config should still be active.
-//    EXPECT_EQ(broadcastCount, 1);
-//
-//    // 3rd processed event.
-//    event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-//    // All activations expired.
-//    event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // Re-activate metric via screen on.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // 4th processed event.
-//    event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // 5th processed event.
-//    event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-//    // Cancel battery saver mode and screen on activation.
-//    event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // Screen-on activation expired.
-//    event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 5);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    // Cancel battery saver mode and screen on activation.
-//    event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 6);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(5, countMetrics.data_size());
-//
-//    auto data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(4);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
-//    auto config = CreateStatsdConfigWithSameDeactivations();
-//
-//    int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-//    int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    long timeBase1 = 1;
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-//    // triggered by screen on event (tracker index 2).
-//    EXPECT_EQ(eventActivationMap.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap.size(), 1u);
-//    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-//    EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
-//    EXPECT_EQ(broadcastCount, 0);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    // Event that should be ignored.
-//    event = CreateAppCrashEvent(111, bucketStartTimeNs + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
-//
-//    // Activate metric via screen on for 2 minutes.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-//    // 1st processed event.
-//    event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-//    // Enable battery saver mode activation for 5 minutes.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-//    // 2nd processed event.
-//    event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-//
-//    // Cancel battery saver mode and screen on activation.
-//    int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
-//    event = CreateScreenBrightnessChangedEvent(64, firstDeactivation);
-//    processor.OnLogEvent(event.get(), firstDeactivation);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-//    // Should be ignored
-//    event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-//    // 3rd processed event.
-//    event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-//
-//    // Cancel battery saver mode activation.
-//    int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
-//    event = CreateScreenBrightnessChangedEvent(140, secondDeactivation);
-//    processor.OnLogEvent(event.get(), secondDeactivation);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-//    // Should be ignored.
-//    event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(3, countMetrics.data_size());
-//
-//    auto data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
-//    auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
-//
-//    int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-//    int64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-//    int uid = 12345;
-//    int64_t cfgId = 98765;
-//    ConfigKey cfgKey(uid, cfgId);
-//
-//    sp<UidMap> m = new UidMap();
-//    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-//    sp<AlarmMonitor> anomalyAlarmMonitor;
-//    sp<AlarmMonitor> subscriberAlarmMonitor;
-//    vector<int64_t> activeConfigsBroadcast;
-//
-//    long timeBase1 = 1;
-//    int broadcastCount = 0;
-//    StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-//            bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-//            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-//                    const vector<int64_t>& activeConfigs) {
-//                broadcastCount++;
-//                EXPECT_EQ(broadcastUid, uid);
-//                activeConfigsBroadcast.clear();
-//                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-//                        activeConfigs.begin(), activeConfigs.end());
-//                return true;
-//            });
-//
-//    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-//    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-//    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-//    EXPECT_TRUE(metricsManager->isConfigValid());
-//    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
-//    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-//    auto& eventActivationMap = metricProducer->mEventActivationMap;
-//    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//    sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
-//    auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
-//    auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
-//
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-//    // triggered by screen on event (tracker index 2).
-//    EXPECT_EQ(eventActivationMap.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-//    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap.size(), 2u);
-//    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-//    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-//    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-//    EXPECT_EQ(eventActivationMap2.size(), 2u);
-//    EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
-//    EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2.size(), 2u);
-//    EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
-//    EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
-//    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    std::unique_ptr<LogEvent> event;
-//
-//    event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-//    event = CreateMoveToForegroundEvent(1111, bucketStartTimeNs + 5);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    EXPECT_EQ(broadcastCount, 0);
-//
-//    // Activated by battery save mode.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 1);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // First processed event.
-//    event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//    event = CreateMoveToForegroundEvent(2222, bucketStartTimeNs + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-//    // Activated by screen on event.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 20);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // 2nd processed event.
-//    // The activation by screen_on event expires, but the one by battery save mode is still active.
-//    event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    event = CreateMoveToForegroundEvent(3333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//    // No new broadcast since the config should still be active.
-//    EXPECT_EQ(broadcastCount, 1);
-//
-//    // 3rd processed event.
-//    event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    event = CreateMoveToForegroundEvent(4444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-//    // All activations expired.
-//    event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    event = CreateMoveToForegroundEvent(5555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 2);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // Re-activate metric via screen on.
-//    event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // 4th processed event.
-//    event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    event = CreateMoveToForegroundEvent(6666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 3);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // 5th processed event.
-//    event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//    event = CreateMoveToForegroundEvent(7777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-//    // Cancel battery saver mode and screen on activation.
-//    event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    // New broadcast since the config is no longer active.
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // Screen-on activation expired.
-//    event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    event = CreateMoveToForegroundEvent(8888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 4);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//    event = CreateMoveToForegroundEvent(9999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-//    // Re-enable battery saver mode activation.
-//    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_TRUE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 5);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-//    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-//    EXPECT_TRUE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_TRUE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    // Cancel battery saver mode and screen on activation.
-//    event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-//    EXPECT_FALSE(metricsManager->isActive());
-//    EXPECT_EQ(broadcastCount, 6);
-//    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-//    EXPECT_FALSE(metricProducer->mIsActive);
-//    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//    EXPECT_FALSE(metricProducer2->mIsActive);
-//    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-//    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-//    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-//    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-//    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-//    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(2, reports.reports(0).metrics_size());
-//    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//    EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
-//
-//    StatsLogReport::CountMetricDataWrapper countMetrics;
-//
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-//    EXPECT_EQ(5, countMetrics.data_size());
-//
-//    auto data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(4);
-//    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//
-//   countMetrics.clear_data();
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(1).count_metrics(), &countMetrics);
-//    EXPECT_EQ(5, countMetrics.data_size());
-//
-//    data = countMetrics.data(0);
-//    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(1);
-//    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(2);
-//    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    // Partial bucket as metric is deactivated.
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(3);
-//    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//    data = countMetrics.data(4);
-//    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* uid field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-//    EXPECT_EQ(1, data.bucket_info_size());
-//    EXPECT_EQ(1, data.bucket_info(0).count());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-//              data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(MetricActivationE2eTest, TestCountMetric) {
+    auto config = CreateStatsdConfig();
+
+    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    long timeBase1 = 1;
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+    // triggered by screen on event (tracker index 2).
+    EXPECT_EQ(eventActivationMap.size(), 2u);
+    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+    std::unique_ptr<LogEvent> event;
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 0);
+
+    // Activated by battery save mode.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+    // First processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+    // Activated by screen on event.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+    // 2nd processed event.
+    // The activation by screen_on event expires, but the one by battery save mode is still active.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    // No new broadcast since the config should still be active.
+    EXPECT_EQ(broadcastCount, 1);
+
+    // 3rd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+    // All activations expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+    // Re-activate metric via screen on.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+                                          android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+    // 4th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                           ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(4, countMetrics.data_size());
+
+    auto data = countMetrics.data(0);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
+    auto config = CreateStatsdConfigWithOneDeactivation();
+
+    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    long timeBase1 = 1;
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+    // triggered by screen on event (tracker index 2).
+    EXPECT_EQ(eventActivationMap.size(), 2u);
+    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap.size(), 1u);
+    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    std::unique_ptr<LogEvent> event;
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 0);
+
+    // Activated by battery save mode.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // First processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+    // Activated by screen on event.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // 2nd processed event.
+    // The activation by screen_on event expires, but the one by battery save mode is still active.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    // No new broadcast since the config should still be active.
+    EXPECT_EQ(broadcastCount, 1);
+
+    // 3rd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+    // All activations expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // Re-activate metric via screen on.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+                                          android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // 4th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // 5th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+    // Cancel battery saver mode activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // Screen-on activation expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 5);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    // Cancel battery saver mode activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 6);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                           ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(5, countMetrics.data_size());
+
+    auto data = countMetrics.data(0);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
+    auto config = CreateStatsdConfigWithTwoDeactivations();
+
+    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    long timeBase1 = 1;
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+    // triggered by screen on event (tracker index 2).
+    EXPECT_EQ(eventActivationMap.size(), 2u);
+    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap.size(), 2u);
+    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    std::unique_ptr<LogEvent> event;
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 0);
+
+    // Activated by battery save mode.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // First processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+    // Activated by screen on event.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // 2nd processed event.
+    // The activation by screen_on event expires, but the one by battery save mode is still active.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    // No new broadcast since the config should still be active.
+    EXPECT_EQ(broadcastCount, 1);
+
+    // 3rd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+    // All activations expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // Re-activate metric via screen on.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+                                          android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // 4th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // 5th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+    // Cancel battery saver mode and screen on activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // Screen-on activation expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 5);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    // Cancel battery saver mode and screen on activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 6);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                           ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(5, countMetrics.data_size());
+
+    auto data = countMetrics.data(0);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
+    auto config = CreateStatsdConfigWithSameDeactivations();
+
+    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    long timeBase1 = 1;
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+    // triggered by screen on event (tracker index 2).
+    EXPECT_EQ(eventActivationMap.size(), 2u);
+    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap.size(), 1u);
+    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+    EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
+    EXPECT_EQ(broadcastCount, 0);
+
+    std::unique_ptr<LogEvent> event;
+
+    // Event that should be ignored.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 1, 111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
+
+    // Activate metric via screen on for 2 minutes.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+    // 1st processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+    // Enable battery saver mode activation for 5 minutes.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+    // 2nd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 40, 333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
+
+    // Cancel battery saver mode and screen on activation.
+    int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
+    event = CreateScreenBrightnessChangedEvent(firstDeactivation, 64);
+    processor.OnLogEvent(event.get(), firstDeactivation);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+    // Should be ignored
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 61 + 80, 444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+    // 3rd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80, 555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
+
+    // Cancel battery saver mode activation.
+    int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
+    event = CreateScreenBrightnessChangedEvent(secondDeactivation, 140);
+    processor.OnLogEvent(event.get(), secondDeactivation);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+    // Should be ignored.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80, 666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                           ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(3, countMetrics.data_size());
+
+    auto data = countMetrics.data(0);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
+    auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
+
+    int64_t bucketStartTimeNs = NS_PER_SEC * 10;  // 10 secs
+    int64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+    int uid = 12345;
+    int64_t cfgId = 98765;
+    ConfigKey cfgKey(uid, cfgId);
+
+    sp<UidMap> m = new UidMap();
+    sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+    sp<AlarmMonitor> anomalyAlarmMonitor;
+    sp<AlarmMonitor> subscriberAlarmMonitor;
+    vector<int64_t> activeConfigsBroadcast;
+
+    long timeBase1 = 1;
+    int broadcastCount = 0;
+    StatsLogProcessor processor(
+            m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+            [](const ConfigKey& key) { return true; },
+            [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+                                                             const vector<int64_t>& activeConfigs) {
+                broadcastCount++;
+                EXPECT_EQ(broadcastUid, uid);
+                activeConfigsBroadcast.clear();
+                activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+                                              activeConfigs.end());
+                return true;
+            });
+
+    processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+    EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+    sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+    EXPECT_TRUE(metricsManager->isConfigValid());
+    EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
+    sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+    auto& eventActivationMap = metricProducer->mEventActivationMap;
+    auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+    sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
+    auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
+    auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
+
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+    // triggered by screen on event (tracker index 2).
+    EXPECT_EQ(eventActivationMap.size(), 2u);
+    EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+    EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap.size(), 2u);
+    EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+    EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+    EXPECT_EQ(eventActivationMap2.size(), 2u);
+    EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
+    EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2.size(), 2u);
+    EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
+    EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
+    EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    std::unique_ptr<LogEvent> event;
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + 5, 1111);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    EXPECT_EQ(broadcastCount, 0);
+
+    // Activated by battery save mode.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 1);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // First processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + 15, 2222);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+    // Activated by screen on event.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // 2nd processed event.
+    // The activation by screen_on event expires, but the one by battery save mode is still active.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 3333);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+    // No new broadcast since the config should still be active.
+    EXPECT_EQ(broadcastCount, 1);
+
+    // 3rd processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 4444);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+    // All activations expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 5555);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+    EXPECT_FALSE(metricsManager->isActive());
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 2);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // Re-activate metric via screen on.
+    event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+                                          android::view::DISPLAY_STATE_ON);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // 4th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 6666);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 3);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // 5th processed event.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 7777);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+    // Cancel battery saver mode and screen on activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+    EXPECT_FALSE(metricsManager->isActive());
+    // New broadcast since the config is no longer active.
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // Screen-on activation expired.
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 8888);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 4);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+    event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 9999);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+    // Re-enable battery saver mode activation.
+    event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_TRUE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 5);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+    EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+    EXPECT_TRUE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_TRUE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    // Cancel battery saver mode and screen on activation.
+    event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+    processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+    EXPECT_FALSE(metricsManager->isActive());
+    EXPECT_EQ(broadcastCount, 6);
+    EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+    EXPECT_FALSE(metricProducer->mIsActive);
+    EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+    EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+    EXPECT_FALSE(metricProducer2->mIsActive);
+    EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+    EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+    EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+    EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+    EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+    EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+    EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+                           ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(2, reports.reports(0).metrics_size());
+    EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+    EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(5, countMetrics.data_size());
+
+    auto data = countMetrics.data(0);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    countMetrics.clear_data();
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics);
+    EXPECT_EQ(5, countMetrics.data_size());
+
+    data = countMetrics.data(0);
+    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(2);
+    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    // Partial bucket as metric is deactivated.
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* uid field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(1, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 7d93fcc..e8fb523 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -97,250 +97,247 @@
 }
 }  // namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
-//// we should use the real API which will clear the data after dump data is called.
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
-//    auto config = CreateStatsdConfig();
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//    int appUid = 123;
-//    auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-//    auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-//    auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-//    auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-//    auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-//    auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-//    auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-//    auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-//    auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-//    auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-//    auto screenTurnedOnEvent =
-//        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                      bucketStartTimeNs + 2);
-//    auto screenTurnedOffEvent =
-//        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                      bucketStartTimeNs + 200);
-//    auto screenTurnedOnEvent2 =
-//        CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                      bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-//    std::vector<AttributionNodeInternal> attributions = {
-//            CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-//    auto syncOnEvent1 =
-//        CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-//    auto syncOffEvent1 =
-//        CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-//    auto syncOnEvent2 =
-//        CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-//    auto moveToBackgroundEvent1 =
-//        CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-//    auto moveToForegroundEvent1 =
-//        CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-//    auto moveToBackgroundEvent2 =
-//        CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-//    auto moveToForegroundEvent2 =
-//        CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-//    /*
-//                    bucket #1                               bucket #2
-//
-//
-//       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
-//    |-------------------------------------|-----------------------------------|---------
-//
-//             |                                           |                        (MoveToBkground)
-//
-//                                             |                               |    (MoveToForeground)
-//
-//                |                                                 |                (SyncIsOn)
-//                                                  |                                (SyncIsOff)
-//          |                                                               |        (ScreenIsOn)
-//                   |                                                               (ScreenIsOff)
-//    */
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(std::move(crashEvent1));
-//    events.push_back(std::move(crashEvent2));
-//    events.push_back(std::move(crashEvent3));
-//    events.push_back(std::move(crashEvent4));
-//    events.push_back(std::move(crashEvent5));
-//    events.push_back(std::move(crashEvent6));
-//    events.push_back(std::move(crashEvent7));
-//    events.push_back(std::move(crashEvent8));
-//    events.push_back(std::move(crashEvent9));
-//    events.push_back(std::move(crashEvent10));
-//    events.push_back(std::move(screenTurnedOnEvent));
-//    events.push_back(std::move(screenTurnedOffEvent));
-//    events.push_back(std::move(screenTurnedOnEvent2));
-//    events.push_back(std::move(syncOnEvent1));
-//    events.push_back(std::move(syncOffEvent1));
-//    events.push_back(std::move(syncOnEvent2));
-//    events.push_back(std::move(moveToBackgroundEvent1));
-//    events.push_back(std::move(moveToForegroundEvent1));
-//    events.push_back(std::move(moveToBackgroundEvent2));
-//    events.push_back(std::move(moveToForegroundEvent2));
-//
-//    sortLogEventsByTimestamp(&events);
-//
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    // Validate dimension value.
-//    EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-//    // Uid field.
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
-//
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
-//    auto config = CreateStatsdConfig();
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(
-//            bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-//    int appUid = 123;
-//    auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-//    auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-//    auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-//    auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-//    auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-//    auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-//    auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-//    auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-//    auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-//    auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-//    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2);
-//    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-//    auto screenTurnedOnEvent2 =
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-//    std::vector<AttributionNodeInternal> attributions = {
-//            CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-//    auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-//    auto syncOffEvent1 =
-//            CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-//    auto syncOnEvent2 =
-//            CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-//    auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-//    auto moveToForegroundEvent1 =
-//            CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-//    auto moveToBackgroundEvent2 =
-//            CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-//    auto moveToForegroundEvent2 =
-//            CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-//    /*
-//                    bucket #1                               bucket #2
-//
-//
-//       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
-//    |-------------------------------------|-----------------------------------|---------
-//
-//             |                                           |                        (MoveToBkground)
-//
-//                                             |                               |    (MoveToForeground)
-//
-//                |                                                 |                (SyncIsOn)
-//                                                  |                                (SyncIsOff)
-//          |                                                               |        (ScreenIsOn)
-//                   |                                                               (ScreenIsOff)
-//    */
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(std::move(crashEvent1));
-//    events.push_back(std::move(crashEvent2));
-//    events.push_back(std::move(crashEvent3));
-//    events.push_back(std::move(crashEvent4));
-//    events.push_back(std::move(crashEvent5));
-//    events.push_back(std::move(crashEvent6));
-//    events.push_back(std::move(crashEvent7));
-//    events.push_back(std::move(crashEvent8));
-//    events.push_back(std::move(crashEvent9));
-//    events.push_back(std::move(crashEvent10));
-//    events.push_back(std::move(screenTurnedOnEvent));
-//    events.push_back(std::move(screenTurnedOffEvent));
-//    events.push_back(std::move(screenTurnedOnEvent2));
-//    events.push_back(std::move(syncOnEvent1));
-//    events.push_back(std::move(syncOffEvent1));
-//    events.push_back(std::move(syncOnEvent2));
-//    events.push_back(std::move(moveToBackgroundEvent1));
-//    events.push_back(std::move(moveToForegroundEvent1));
-//    events.push_back(std::move(moveToBackgroundEvent2));
-//    events.push_back(std::move(moveToForegroundEvent2));
-//
-//    sortLogEventsByTimestamp(&events);
-//
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
-//    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-//    // Validate dimension value.
-//    EXPECT_EQ(data.dimensions_in_what().field(),
-//              android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-//    // Uid field.
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-//    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
+// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
+// we should use the real API which will clear the data after dump data is called.
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
+    auto config = CreateStatsdConfig();
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int appUid = 123;
+    auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+    auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+    auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+    auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+    auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+    auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+    auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+    auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+    auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+    auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    auto screenTurnedOnEvent2 =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+    std::vector<int> attributionUids = {appUid, appUid + 1};
+    std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+    auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+                                             attributionTags, "ReadEmail");
+    auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+                                            attributionTags, "ReadEmail");
+    auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+                                             attributionUids, attributionTags, "ReadDoc");
+
+    auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+    auto moveToForegroundEvent1 =
+            CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+    auto moveToBackgroundEvent2 =
+            CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+    auto moveToForegroundEvent2 =
+            CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+    /*
+                    bucket #1                               bucket #2
+
+
+       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
+    |-------------------------------------|-----------------------------------|---------
+
+             |                                           |                        (MoveToBkground)
+
+                                             |                               |    (MoveToForeground)
+
+                |                                                 |                (SyncIsOn)
+                                                  |                                (SyncIsOff)
+          |                                                               |        (ScreenIsOn)
+                   |                                                               (ScreenIsOff)
+    */
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(std::move(crashEvent1));
+    events.push_back(std::move(crashEvent2));
+    events.push_back(std::move(crashEvent3));
+    events.push_back(std::move(crashEvent4));
+    events.push_back(std::move(crashEvent5));
+    events.push_back(std::move(crashEvent6));
+    events.push_back(std::move(crashEvent7));
+    events.push_back(std::move(crashEvent8));
+    events.push_back(std::move(crashEvent9));
+    events.push_back(std::move(crashEvent10));
+    events.push_back(std::move(screenTurnedOnEvent));
+    events.push_back(std::move(screenTurnedOffEvent));
+    events.push_back(std::move(screenTurnedOnEvent2));
+    events.push_back(std::move(syncOnEvent1));
+    events.push_back(std::move(syncOffEvent1));
+    events.push_back(std::move(syncOnEvent2));
+    events.push_back(std::move(moveToBackgroundEvent1));
+    events.push_back(std::move(moveToForegroundEvent1));
+    events.push_back(std::move(moveToBackgroundEvent2));
+    events.push_back(std::move(moveToForegroundEvent2));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    // Validate dimension value.
+    EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+    // Uid field.
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
+
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
+    auto config = CreateStatsdConfig();
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    int appUid = 123;
+    auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+    auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+    auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+    auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+    auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+    auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+    auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+    auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+    auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+    auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    auto screenTurnedOnEvent2 =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+    std::vector<int> attributionUids = {appUid, appUid + 1};
+    std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+    auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+                                             attributionTags, "ReadEmail");
+    auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+                                            attributionTags, "ReadEmail");
+    auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+                                             attributionUids, attributionTags, "ReadDoc");
+
+    auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+    auto moveToForegroundEvent1 =
+            CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+    auto moveToBackgroundEvent2 =
+            CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+    auto moveToForegroundEvent2 =
+            CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+    /*
+                    bucket #1                               bucket #2
+
+
+       |      |   |  |                      |   |          |        |   |   |     (crashEvents)
+    |-------------------------------------|-----------------------------------|---------
+
+             |                                           |                        (MoveToBkground)
+
+                                             |                               |    (MoveToForeground)
+
+                |                                                 |                (SyncIsOn)
+                                                  |                                (SyncIsOff)
+          |                                                               |        (ScreenIsOn)
+                   |                                                               (ScreenIsOff)
+    */
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(std::move(crashEvent1));
+    events.push_back(std::move(crashEvent2));
+    events.push_back(std::move(crashEvent3));
+    events.push_back(std::move(crashEvent4));
+    events.push_back(std::move(crashEvent5));
+    events.push_back(std::move(crashEvent6));
+    events.push_back(std::move(crashEvent7));
+    events.push_back(std::move(crashEvent8));
+    events.push_back(std::move(crashEvent9));
+    events.push_back(std::move(crashEvent10));
+    events.push_back(std::move(screenTurnedOnEvent));
+    events.push_back(std::move(screenTurnedOffEvent));
+    events.push_back(std::move(screenTurnedOnEvent2));
+    events.push_back(std::move(syncOnEvent1));
+    events.push_back(std::move(syncOffEvent1));
+    events.push_back(std::move(syncOnEvent2));
+    events.push_back(std::move(moveToBackgroundEvent1));
+    events.push_back(std::move(moveToForegroundEvent1));
+    events.push_back(std::move(moveToBackgroundEvent2));
+    events.push_back(std::move(moveToForegroundEvent2));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
+    auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+    // Validate dimension value.
+    EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+    // Uid field.
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+    EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 9ec831b..b975907 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -113,96 +113,107 @@
 }
 }  // anonymous namespace
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-//    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-//    SendConfig(service, MakeConfig());
-//    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-//                                             // initialized with.
-//
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
-//
-//    ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
-//    // Expect no metrics since the bucket has not finished yet.
-//    EXPECT_EQ(1, report.metrics_size());
-//    EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-//    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-//    SendConfig(service, MakeConfig());
-//    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-//                                             // initialized with.
-//
-//    // Force the uidmap to update at timestamp 2.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-//    // This is a new installation, so there shouldn't be a split (should be same as the without
-//    // split case).
-//    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-//                               String16(""));
-//    // Goes into the second bucket.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-//    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-//    EXPECT_EQ(1, report.metrics_size());
-//    EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-//    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-//    SendConfig(service, MakeConfig());
-//    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-//                                             // initialized with.
-//    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-//                                {String16("")});
-//
-//    // Force the uidmap to update at timestamp 2.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-//    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-//                               String16(""));
-//    // Goes into the second bucket.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-//    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-//    backfillStartEndTimestamp(&report);
-//
-//    ASSERT_EQ(1, report.metrics_size());
-//    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-//    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-//    EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-//                    has_start_bucket_elapsed_nanos());
-//    EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-//                    has_end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-//    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-//    SendConfig(service, MakeConfig());
-//    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
-//                                             // initialized with.
-//    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-//                                {String16("")});
-//
-//    // Force the uidmap to update at timestamp 2.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-//    service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
-//    // Goes into the second bucket.
-//    service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-//    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-//    backfillStartEndTimestamp(&report);
-//
-//    ASSERT_EQ(1, report.metrics_size());
-//    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-//    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-//    EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-//                    has_start_bucket_elapsed_nanos());
-//    EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-//                    has_end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
+TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
+    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+    SendConfig(service, MakeConfig());
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
+
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get());
+
+    ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
+    // Expect no metrics since the bucket has not finished yet.
+    EXPECT_EQ(1, report.metrics_size());
+    EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
+    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+    SendConfig(service, MakeConfig());
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
+
+    // Force the uidmap to update at timestamp 2.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+    // This is a new installation, so there shouldn't be a split (should be same as the without
+    // split case).
+    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+                                String16(""));
+    // Goes into the second bucket.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+    EXPECT_EQ(1, report.metrics_size());
+    EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
+    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+    SendConfig(service, MakeConfig());
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
+    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+                                {String16("")});
+
+    // Force the uidmap to update at timestamp 2.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+    service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+                                String16(""));
+    // Goes into the second bucket.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+    backfillStartEndTimestamp(&report);
+
+    ASSERT_EQ(1, report.metrics_size());
+    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+    EXPECT_TRUE(report.metrics(0)
+                        .count_metrics()
+                        .data(0)
+                        .bucket_info(0)
+                        .has_start_bucket_elapsed_nanos());
+    EXPECT_TRUE(report.metrics(0)
+                        .count_metrics()
+                        .data(0)
+                        .bucket_info(0)
+                        .has_end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
+    shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+    SendConfig(service, MakeConfig());
+    int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                             // initialized with.
+    service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+                                {String16("")});
+
+    // Force the uidmap to update at timestamp 2.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+    service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
+    // Goes into the second bucket.
+    service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+    ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+    backfillStartEndTimestamp(&report);
+
+    ASSERT_EQ(1, report.metrics_size());
+    ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+    ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+    EXPECT_TRUE(report.metrics(0)
+                        .count_metrics()
+                        .data(0)
+                        .bucket_info(0)
+                        .has_start_bucket_elapsed_nanos());
+    EXPECT_TRUE(report.metrics(0)
+                        .count_metrics()
+                        .data(0)
+                        .bucket_info(0)
+                        .has_end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
 
 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
     shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 99dbaf1..a87bb71 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -64,317 +64,313 @@
 
 }  // namespace
 
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ValueMetricE2eTest, TestPulledEvents) {
-//    auto config = CreateStatsdConfig();
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             android::util::SUBSYSTEM_SLEEP_STATE);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//
-//    // When creating the config, the value metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& expectedPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-//    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                        configAddedTimeNs + 55);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + 65);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + 75);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-//    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + 2 * bucketSizeNs + 15);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + 4 * bucketSizeNs + 11);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-//    EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-//    auto data = valueMetrics.data(0);
-//    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    // We have 4 buckets, the first one was incomplete since the condition was unknown.
-//    EXPECT_EQ(4, data.bucket_info_size());
-//
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(2).values_size());
-//
-//    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(3).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
-//    auto config = CreateStatsdConfig();
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    // 10 mins == 2 bucket durations.
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             android::util::SUBSYSTEM_SLEEP_STATE);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//
-//    // When creating the config, the value metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& expectedPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-//    // Screen off/on/off events.
-//    auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                        configAddedTimeNs + 55);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + 65);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + 75);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
-//    // future, data will be skipped.
-//    processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-//    // This screen state change will start a new bucket.
-//    screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-//                                                       configAddedTimeNs + 4 * bucketSizeNs + 65);
-//    processor->OnLogEvent(screenOnEvent.get());
-//
-//    // The alarm is delayed but we already created a bucket thanks to the screen state condition.
-//    // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
-//    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-//    screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-//                                                   configAddedTimeNs + 6 * bucketSizeNs + 31);
-//    processor->OnLogEvent(screenOffEvent.get());
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-//    EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-//    auto data = valueMetrics.data(0);
-//    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    EXPECT_EQ(3, data.bucket_info_size());
-//
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-//    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-//    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, data.bucket_info(2).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
-//    auto config = CreateStatsdConfig(false);
-//    int64_t baseTimeNs = getElapsedRealtimeNs();
-//    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-//    int64_t bucketSizeNs =
-//        TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-//    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-//    *config.add_atom_matcher() = batterySaverStartMatcher;
-//    const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-//    auto metric_activation = config.add_metric_activation();
-//    metric_activation->set_metric_id(metricId);
-//    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-//    auto event_activation = metric_activation->add_event_activation();
-//    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-//    event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-//    ConfigKey cfgKey;
-//    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-//                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
-//                                             android::util::SUBSYSTEM_SLEEP_STATE);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    processor->mPullerManager->ForceClearPullerCache();
-//
-//    int startBucketNum = processor->mMetricsManagers.begin()->second->
-//            mAllMetricProducers[0]->getCurrentBucketNum();
-//    EXPECT_GT(startBucketNum, (int64_t)0);
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // When creating the config, the value metric producer should register the alarm at the
-//    // end of the current bucket.
-//    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-//    EXPECT_EQ(bucketSizeNs,
-//              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-//    int64_t& expectedPullTimeNs =
-//            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-//    // Pulling alarm arrives on time and reset the sequential pulling alarm.
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    // Activate the metric. A pull occurs here
-//    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-//    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-//    processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns.
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-//    // Create random event to deactivate metric.
-//    auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-//    processor->OnLogEvent(deactivationEvent.get());
-//    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 3);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
-//
-//    processor->informPullAlarmFired(expectedPullTimeNs + 4);
-//    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(1, reports.reports_size());
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    StatsLogReport::ValueMetricDataWrapper valueMetrics;
-//    sortMetricDataByDimensionsValue(
-//            reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-//    EXPECT_GT((int)valueMetrics.data_size(), 0);
-//
-//    auto data = valueMetrics.data(0);
-//    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-//    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-//    EXPECT_EQ(1 /* subsystem name field */,
-//              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-//    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-//    // We have 2 full buckets, the two surrounding the activation are dropped.
-//    EXPECT_EQ(2, data.bucket_info_size());
-//
-//    auto bucketInfo = data.bucket_info(0);
-//    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, bucketInfo.values_size());
-//
-//    bucketInfo = data.bucket_info(1);
-//    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-//    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//    EXPECT_EQ(1, bucketInfo.values_size());
-//}
+TEST(ValueMetricE2eTest, TestPulledEvents) {
+    auto config = CreateStatsdConfig();
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
+                                             android::util::SUBSYSTEM_SLEEP_STATE);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the value metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& expectedPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+    auto screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 2 * bucketSizeNs + 15,
+                                                  android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 11,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::ValueMetricDataWrapper valueMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+    EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+    auto data = valueMetrics.data(0);
+    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    // We have 4 buckets, the first one was incomplete since the condition was unknown.
+    EXPECT_EQ(4, data.bucket_info_size());
+
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(2).values_size());
+
+    EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(3).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
+    auto config = CreateStatsdConfig();
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    // 10 mins == 2 bucket durations.
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
+                                             android::util::SUBSYSTEM_SLEEP_STATE);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+
+    // When creating the config, the value metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& expectedPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+    // Screen off/on/off events.
+    auto screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    auto screenOnEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    screenOffEvent =
+            CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
+    // future, data will be skipped.
+    processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+    // This screen state change will start a new bucket.
+    screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 65,
+                                                  android::view::DISPLAY_STATE_ON);
+    processor->OnLogEvent(screenOnEvent.get());
+
+    // The alarm is delayed but we already created a bucket thanks to the screen state condition.
+    // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
+    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+    screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 6 * bucketSizeNs + 31,
+                                                   android::view::DISPLAY_STATE_OFF);
+    processor->OnLogEvent(screenOffEvent.get());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::ValueMetricDataWrapper valueMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+    EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+    auto data = valueMetrics.data(0);
+    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    EXPECT_EQ(3, data.bucket_info_size());
+
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+    EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+    EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(2).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
+    auto config = CreateStatsdConfig(false);
+    int64_t baseTimeNs = getElapsedRealtimeNs();
+    int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+    auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+    *config.add_atom_matcher() = batterySaverStartMatcher;
+    const int64_t ttlNs = 2 * bucketSizeNs;  // Two buckets.
+    auto metric_activation = config.add_metric_activation();
+    metric_activation->set_metric_id(metricId);
+    metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+    auto event_activation = metric_activation->add_event_activation();
+    event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+    event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+                                             SharedRefBase::make<FakeSubsystemSleepCallback>(),
+                                             android::util::SUBSYSTEM_SLEEP_STATE);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    processor->mPullerManager->ForceClearPullerCache();
+
+    int startBucketNum = processor->mMetricsManagers.begin()
+                                 ->second->mAllMetricProducers[0]
+                                 ->getCurrentBucketNum();
+    EXPECT_GT(startBucketNum, (int64_t)0);
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // When creating the config, the value metric producer should register the alarm at the
+    // end of the current bucket.
+    EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+    EXPECT_EQ(bucketSizeNs,
+              processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+    int64_t& expectedPullTimeNs =
+            processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+    // Pulling alarm arrives on time and reset the sequential pulling alarm.
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);  // 15 mins + 1 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    // Activate the metric. A pull occurs here
+    const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000);  // 2 millis.
+    auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+    processor->OnLogEvent(batterySaverOnEvent.get());  // 15 mins + 2 ms.
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 1);  // 20 mins + 1 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 2);  // 25 mins + 2 ns.
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+    // Create random event to deactivate metric.
+    auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+    processor->OnLogEvent(deactivationEvent.get());
+    EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 3);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
+
+    processor->informPullAlarmFired(expectedPullTimeNs + 4);
+    EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+                            ADB_DUMP, FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(1, reports.reports_size());
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    StatsLogReport::ValueMetricDataWrapper valueMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+    EXPECT_GT((int)valueMetrics.data_size(), 0);
+
+    auto data = valueMetrics.data(0);
+    EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+    EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+    EXPECT_EQ(1 /* subsystem name field */,
+              data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+    EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+    // We have 2 full buckets, the two surrounding the activation are dropped.
+    EXPECT_EQ(2, data.bucket_info_size());
+
+    auto bucketInfo = data.bucket_info(0);
+    EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, bucketInfo.values_size());
+
+    bucketInfo = data.bucket_info(1);
+    EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+    EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, bucketInfo.values_size());
+}
 
 /**
  * Test initialization of a simple value metric that is sliced by a state.
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 21092e2..ddd8f95 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -61,292 +61,290 @@
     return config;
 }
 
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-                                                      CreateAttribution(222, "GMSCoreModule1"),
-                                                      CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids1 = {111, 222, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
 
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
-                                                      CreateAttribution(222, "GMSCoreModule1"),
-                                                      CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids2 = {111, 222, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
 
-// TODO(b/149590301): Update this helper to use new socket schema.
-///*
-//Events:
-//Screen off is met from (200ns,1 min+500ns].
-//Acquire event for wl1 from 2ns to 1min+2ns
-//Acquire event for wl2 from 1min-10ns to 2min-15ns
-//*/
-//void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//
-//    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-//    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-//            android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-//    auto screenTurnedOnEvent2 =
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-//                                          bucketStartTimeNs + bucketSizeNs + 500);
-//
-//    auto acquireEvent1 = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-//    auto releaseEvent1 =
-//            CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-//    auto acquireEvent2 =
-//            CreateAcquireWakelockEvent(attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10);
-//    auto releaseEvent2 = CreateReleaseWakelockEvent(attributions2, "wl2",
-//                                                    bucketStartTimeNs + 2 * bucketSizeNs - 15);
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//
-//    events.push_back(std::move(screenTurnedOnEvent));
-//    events.push_back(std::move(screenTurnedOffEvent));
-//    events.push_back(std::move(screenTurnedOnEvent2));
-//    events.push_back(std::move(acquireEvent1));
-//    events.push_back(std::move(acquireEvent2));
-//    events.push_back(std::move(releaseEvent1));
-//    events.push_back(std::move(releaseEvent2));
-//
-//    sortLogEventsByTimestamp(&events);
-//
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//}
+/*
+Events:
+Screen off is met from (200ns,1 min+500ns].
+Acquire event for wl1 from 2ns to 1min+2ns
+Acquire event for wl2 from 1min-10ns to 2min-15ns
+*/
+void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+    auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+    auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+            bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+    auto screenTurnedOnEvent2 =
+            CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 500,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+    auto acquireEvent1 = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+                                                    attributionTags1, "wl1");
+    auto releaseEvent1 = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2,
+                                                    attributionUids1, attributionTags1, "wl1");
+    auto acquireEvent2 = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 10,
+                                                    attributionUids2, attributionTags2, "wl2");
+    auto releaseEvent2 = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 15,
+                                                    attributionUids2, attributionTags2, "wl2");
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+
+    events.push_back(std::move(screenTurnedOnEvent));
+    events.push_back(std::move(screenTurnedOffEvent));
+    events.push_back(std::move(screenTurnedOnEvent2));
+    events.push_back(std::move(acquireEvent1));
+    events.push_back(std::move(acquireEvent2));
+    events.push_back(std::move(releaseEvent1));
+    events.push_back(std::move(releaseEvent2));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+}
 
 }  // namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::SUM);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // Validate dimension value.
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, 111);
-//    // Validate bucket info.
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-//    data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // The wakelock holding interval starts from the screen off event and to the end of the 1st
-//    // bucket.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::SUM);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//    // Dump the report after the end of 2nd bucket.
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // Validate dimension value.
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, 111);
-//    // Two output buckets.
-//    // The wakelock holding interval in the 1st bucket starts from the screen off event and to
-//    // the end of the 1st bucket.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
-//              bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
-//    // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
-//    // ends at the second screen on event.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
-//}
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::SUM);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    vector<uint8_t> buffer;
-//    ConfigMetricsReportList reports;
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 2 * bucketSizeNs + 90));
-//    events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-//                                                bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//    events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-//                                                bucketStartTimeNs + 5 * bucketSizeNs + 100));
-//    sortLogEventsByTimestamp(&events);
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, 111);
-//    // The last wakelock holding spans 4 buckets.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
-//    EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
-//    EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
-//    EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//
-//    EXPECT_EQ(reports.reports_size(), 1);
-//
-//    // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
-//    // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
-//    // itself.
-//    EXPECT_EQ(1, reports.reports(0).metrics_size());
-//    EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//    // Dump the report after the end of 2nd bucket. One dimension with one bucket.
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    // Validate dimension value.
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, 111);
-//    // The max is acquire event for wl1 to screen off start.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
-//    ConfigKey cfgKey;
-//    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-//    uint64_t bucketStartTimeNs = 10000000000;
-//    uint64_t bucketSizeNs =
-//            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-//    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//    FeedEvents(config, processor);
-//    ConfigMetricsReportList reports;
-//    vector<uint8_t> buffer;
-//
-//    std::vector<std::unique_ptr<LogEvent>> events;
-//    events.push_back(
-//            CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-//                                          bucketStartTimeNs + 2 * bucketSizeNs + 90));
-//    events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-//                                                bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//    events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-//                                                bucketStartTimeNs + 5 * bucketSizeNs + 100));
-//    sortLogEventsByTimestamp(&events);
-//    for (const auto& event : events) {
-//        processor->OnLogEvent(event.get());
-//    }
-//
-//    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-//                            ADB_DUMP, FAST, &buffer);
-//    EXPECT_TRUE(buffer.size() > 0);
-//    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-//    backfillDimensionPath(&reports);
-//    backfillStringInReport(&reports);
-//    backfillStartEndTimestamp(&reports);
-//    EXPECT_EQ(reports.reports_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-//    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//    ValidateAttributionUidDimension(data.dimensions_in_what(),
-//                                    android::util::WAKELOCK_STATE_CHANGED, 111);
-//    // The last wakelock holding spans 4 buckets.
-//    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
-//    EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
-//              bucketStartTimeNs + 5 * bucketSizeNs);
-//    EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
-//              bucketStartTimeNs + 6 * bucketSizeNs);
-//}
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::SUM);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // Validate bucket info.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+    data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // The wakelock holding interval starts from the screen off event and to the end of the 1st
+    // bucket.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::SUM);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    // Dump the report after the end of 2nd bucket.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // Two output buckets.
+    // The wakelock holding interval in the 1st bucket starts from the screen off event and to
+    // the end of the 1st bucket.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
+              bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
+    // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
+    // ends at the second screen on event.
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::SUM);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    vector<uint8_t> buffer;
+    ConfigMetricsReportList reports;
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+                                                attributionUids1, attributionTags1, "wl3"));
+    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+                                                attributionUids1, attributionTags1, "wl3"));
+    sortLogEventsByTimestamp(&events);
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The last wakelock holding spans 4 buckets.
+    EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
+    EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+
+    EXPECT_EQ(reports.reports_size(), 1);
+
+    // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
+    // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
+    // itself.
+    EXPECT_EQ(1, reports.reports(0).metrics_size());
+    EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    // Dump the report after the end of 2nd bucket. One dimension with one bucket.
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    // Validate dimension value.
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The max is acquire event for wl1 to screen off start.
+    EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
+    ConfigKey cfgKey;
+    auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+    uint64_t bucketStartTimeNs = 10000000000;
+    uint64_t bucketSizeNs =
+            TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+    FeedEvents(config, processor);
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    events.push_back(
+            CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+                                          android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+    events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+                                                attributionUids1, attributionTags1, "wl3"));
+    events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+                                                attributionUids1, attributionTags1, "wl3"));
+    sortLogEventsByTimestamp(&events);
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+                            FAST, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    backfillDimensionPath(&reports);
+    backfillStringInReport(&reports);
+    backfillStartEndTimestamp(&reports);
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+    auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+    ValidateAttributionUidDimension(data.dimensions_in_what(),
+                                    android::util::WAKELOCK_STATE_CHANGED, 111);
+    // The last wakelock holding spans 4 buckets.
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
+              bucketStartTimeNs + 5 * bucketSizeNs);
+    EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
+              bucketStartTimeNs + 6 * bucketSizeNs);
+}
 
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
index c0b4f43..e8200d5 100644
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -15,11 +15,14 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <stdio.h>
+
 #include <chrono>
 #include <thread>
 #include <vector>
+
 #include "../metrics/metrics_test_helper.h"
 #include "src/stats_log_util.h"
+#include "stats_event.h"
 #include "tests/statsd_test_util.h"
 
 #ifdef __ANDROID__
@@ -57,13 +60,22 @@
 
 FakePuller puller;
 
-// TODO(b/149590301): Update this helper to use new socket schema.
-//shared_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
-//    shared_ptr<LogEvent> event = make_shared<LogEvent>(pullTagId, eventTimeNs);
-//    event->write(value);
-//    event->init();
-//    return event;
-//}
+std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, pullTagId);
+    AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+
+    AStatsEvent_writeInt64(statsEvent, value);
+    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;
+}
 
 class StatsPullerTest : public ::testing::Test {
 public:
@@ -80,149 +92,148 @@
 
 }  // Anonymous namespace.
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST_F(StatsPullerTest, PullSuccess) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = true;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_TRUE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(1, dataHolder.size());
-//    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-//    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-//    EXPECT_EQ(1, dataHolder[0]->size());
-//    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-//    sleep_for(std::chrono::seconds(1));
-//
-//    pullData.clear();
-//    pullData.push_back(createSimpleEvent(2222L, 44));
-//
-//    pullSuccess = true;
-//
-//    EXPECT_TRUE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(1, dataHolder.size());
-//    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-//    EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
-//    EXPECT_EQ(1, dataHolder[0]->size());
-//    EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailAfterSuccess) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = true;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_TRUE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(1, dataHolder.size());
-//    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-//    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-//    EXPECT_EQ(1, dataHolder[0]->size());
-//    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-//    sleep_for(std::chrono::seconds(1));
-//
-//    pullData.clear();
-//    pullData.push_back(createSimpleEvent(2222L, 44));
-//
-//    pullSuccess = false;
-//    dataHolder.clear();
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//
-//    pullSuccess = true;
-//    dataHolder.clear();
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
-//TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//    pullSuccess = true;
-//    // timeout is 0.5
-//    pullDelayNs = (long)(0.8 * NS_PER_SEC);
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//
-//    pullData.clear();
-//    pullData.push_back(createSimpleEvent(2222L, 44));
-//
-//    pullSuccess = true;
-//    dataHolder.clear();
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullFail) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = false;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTakeTooLong) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = true;
-//    pullDelayNs = NS_PER_SEC;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTooFast) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = true;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_TRUE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(1, dataHolder.size());
-//    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-//    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-//    EXPECT_EQ(1, dataHolder[0]->size());
-//    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-//    pullData.clear();
-//    pullData.push_back(createSimpleEvent(2222L, 44));
-//
-//    pullSuccess = true;
-//
-//    dataHolder.clear();
-//    EXPECT_TRUE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(1, dataHolder.size());
-//    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-//    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-//    EXPECT_EQ(1, dataHolder[0]->size());
-//    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailsAndTooFast) {
-//    pullData.push_back(createSimpleEvent(1111L, 33));
-//
-//    pullSuccess = false;
-//
-//    vector<std::shared_ptr<LogEvent>> dataHolder;
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//
-//    pullData.clear();
-//    pullData.push_back(createSimpleEvent(2222L, 44));
-//
-//    pullSuccess = true;
-//
-//    EXPECT_FALSE(puller.Pull(&dataHolder));
-//    EXPECT_EQ(0, dataHolder.size());
-//}
+TEST_F(StatsPullerTest, PullSuccess) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = true;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_TRUE(puller.Pull(&dataHolder));
+    EXPECT_EQ(1, dataHolder.size());
+    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+    EXPECT_EQ(1, dataHolder[0]->size());
+    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+    sleep_for(std::chrono::seconds(1));
+
+    pullData.clear();
+    pullData.push_back(createSimpleEvent(2222L, 44));
+
+    pullSuccess = true;
+
+    EXPECT_TRUE(puller.Pull(&dataHolder));
+    EXPECT_EQ(1, dataHolder.size());
+    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+    EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
+    EXPECT_EQ(1, dataHolder[0]->size());
+    EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailAfterSuccess) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = true;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_TRUE(puller.Pull(&dataHolder));
+    EXPECT_EQ(1, dataHolder.size());
+    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+    EXPECT_EQ(1, dataHolder[0]->size());
+    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+    sleep_for(std::chrono::seconds(1));
+
+    pullData.clear();
+    pullData.push_back(createSimpleEvent(2222L, 44));
+
+    pullSuccess = false;
+    dataHolder.clear();
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+
+    pullSuccess = true;
+    dataHolder.clear();
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+}
+
+// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
+TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+    pullSuccess = true;
+    // timeout is 0.5
+    pullDelayNs = (long)(0.8 * NS_PER_SEC);
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+
+    pullData.clear();
+    pullData.push_back(createSimpleEvent(2222L, 44));
+
+    pullSuccess = true;
+    dataHolder.clear();
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullFail) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = false;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTakeTooLong) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = true;
+    pullDelayNs = NS_PER_SEC;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTooFast) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = true;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_TRUE(puller.Pull(&dataHolder));
+    EXPECT_EQ(1, dataHolder.size());
+    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+    EXPECT_EQ(1, dataHolder[0]->size());
+    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+    pullData.clear();
+    pullData.push_back(createSimpleEvent(2222L, 44));
+
+    pullSuccess = true;
+
+    dataHolder.clear();
+    EXPECT_TRUE(puller.Pull(&dataHolder));
+    EXPECT_EQ(1, dataHolder.size());
+    EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+    EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+    EXPECT_EQ(1, dataHolder[0]->size());
+    EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailsAndTooFast) {
+    pullData.push_back(createSimpleEvent(1111L, 33));
+
+    pullSuccess = false;
+
+    vector<std::shared_ptr<LogEvent>> dataHolder;
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+
+    pullData.clear();
+    pullData.push_back(createSimpleEvent(2222L, 44));
+
+    pullSuccess = true;
+
+    EXPECT_FALSE(puller.Pull(&dataHolder));
+    EXPECT_EQ(0, dataHolder.size());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index 81590a2..f21954f2 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -13,12 +13,16 @@
 // limitations under the License.
 
 #include "external/puller_util.h"
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <stdio.h>
+
 #include <vector>
-#include "statslog.h"
+
 #include "../metrics/metrics_test_helper.h"
+#include "stats_event.h"
+#include "statslog.h"
 
 #ifdef __ANDROID__
 
@@ -58,212 +62,187 @@
     ret.push_back(vec);
   }
 }
+
+std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int data1, int data2) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, uidAtomTagId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    AStatsEvent_writeInt32(statsEvent, data1);
+    AStatsEvent_writeInt32(statsEvent, data2);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+    std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+    return logEvent;
+}
+
+std::shared_ptr<LogEvent> makeNonUidAtomLogEvent(uint64_t timestampNs, int data1) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, nonUidAtomTagId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, data1);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+    std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+    return logEvent;
+}
+
 }  // anonymous namespace
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(puller_util, MergeNoDimension) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  // 30->22->31
-//  event->write(isolatedUid);
-//  event->write(hostNonAdditiveData);
-//  event->write(isolatedAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 20->22->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(hostNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-//      .WillRepeatedly(Return(hostUid));
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-//      .WillRepeatedly(ReturnArg<0>());
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-//  vector<vector<int>> actual;
-//  extractIntoVector(inputData, actual);
-//  vector<int> expectedV1 = {20, 22, 52};
-//  EXPECT_EQ(1, (int)actual.size());
-//  EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, MergeWithDimension) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  // 30->32->31
-//  event->write(isolatedUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(isolatedAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 20->32->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 20->22->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(hostNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-//      .WillRepeatedly(Return(hostUid));
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-//      .WillRepeatedly(ReturnArg<0>());
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-//  vector<vector<int>> actual;
-//  extractIntoVector(inputData, actual);
-//  vector<int> expectedV1 = {20, 22, 21};
-//  vector<int> expectedV2 = {20, 32, 52};
-//  EXPECT_EQ(2, (int)actual.size());
-//  EXPECT_THAT(actual, Contains(expectedV1));
-//  EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, NoMergeHostUidOnly) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  // 20->32->31
-//  event->write(hostUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(isolatedAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 20->22->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(hostNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-//      .WillRepeatedly(Return(hostUid));
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-//      .WillRepeatedly(ReturnArg<0>());
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-//  // 20->32->31
-//  // 20->22->21
-//  vector<vector<int>> actual;
-//  extractIntoVector(inputData, actual);
-//  vector<int> expectedV1 = {20, 32, 31};
-//  vector<int> expectedV2 = {20, 22, 21};
-//  EXPECT_EQ(2, (int)actual.size());
-//  EXPECT_THAT(actual, Contains(expectedV1));
-//  EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, IsolatedUidOnly) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  // 30->32->31
-//  event->write(hostUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(isolatedAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 30->22->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(hostNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-//      .WillRepeatedly(Return(hostUid));
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-//      .WillRepeatedly(ReturnArg<0>());
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-//  // 20->32->31
-//  // 20->22->21
-//  vector<vector<int>> actual;
-//  extractIntoVector(inputData, actual);
-//  vector<int> expectedV1 = {20, 32, 31};
-//  vector<int> expectedV2 = {20, 22, 21};
-//  EXPECT_EQ(2, (int)actual.size());
-//  EXPECT_THAT(actual, Contains(expectedV1));
-//  EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  // 30->32->31
-//  event->write(isolatedUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(isolatedAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 31->32->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(isolatedUid + 1);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  // 20->32->21
-//  event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-//  event->write(hostUid);
-//  event->write(isolatedNonAdditiveData);
-//  event->write(hostAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-//  vector<vector<int>> actual;
-//  extractIntoVector(inputData, actual);
-//  vector<int> expectedV1 = {20, 32, 73};
-//  EXPECT_EQ(1, (int)actual.size());
-//  EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, NoNeedToMerge) {
-//  vector<shared_ptr<LogEvent>> inputData;
-//  shared_ptr<LogEvent> event =
-//      make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-//  // 32
-//  event->write(isolatedNonAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  event = make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-//  // 22
-//  event->write(hostNonAdditiveData);
-//  event->init();
-//  inputData.push_back(event);
-//
-//  sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-//  mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
-//
-//  EXPECT_EQ(2, (int)inputData.size());
-//}
+TEST(puller_util, MergeNoDimension) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 30->22->31
+    inputData.push_back(
+            makeUidLogEvent(timestamp, isolatedUid, hostNonAdditiveData, isolatedAdditiveData));
+
+    // 20->22->21
+    inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+    vector<vector<int>> actual;
+    extractIntoVector(inputData, actual);
+    vector<int> expectedV1 = {20, 22, 52};
+    EXPECT_EQ(1, (int)actual.size());
+    EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, MergeWithDimension) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 30->32->31
+    inputData.push_back(
+            makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+    // 20->32->21
+    inputData.push_back(
+            makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+    // 20->22->21
+    inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+    vector<vector<int>> actual;
+    extractIntoVector(inputData, actual);
+    vector<int> expectedV1 = {20, 22, 21};
+    vector<int> expectedV2 = {20, 32, 52};
+    EXPECT_EQ(2, (int)actual.size());
+    EXPECT_THAT(actual, Contains(expectedV1));
+    EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, NoMergeHostUidOnly) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 20->32->31
+    inputData.push_back(
+            makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+    // 20->22->21
+    inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+    // 20->32->31
+    // 20->22->21
+    vector<vector<int>> actual;
+    extractIntoVector(inputData, actual);
+    vector<int> expectedV1 = {20, 32, 31};
+    vector<int> expectedV2 = {20, 22, 21};
+    EXPECT_EQ(2, (int)actual.size());
+    EXPECT_THAT(actual, Contains(expectedV1));
+    EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, IsolatedUidOnly) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 30->32->31
+    inputData.push_back(
+            makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+    // 30->22->21
+    inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+    // 20->32->31
+    // 20->22->21
+    vector<vector<int>> actual;
+    extractIntoVector(inputData, actual);
+    vector<int> expectedV1 = {20, 32, 31};
+    vector<int> expectedV2 = {20, 22, 21};
+    EXPECT_EQ(2, (int)actual.size());
+    EXPECT_THAT(actual, Contains(expectedV1));
+    EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 30->32->31
+    inputData.push_back(
+            makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+    // 31->32->21
+    inputData.push_back(
+            makeUidLogEvent(timestamp, isolatedUid + 1, isolatedNonAdditiveData, hostAdditiveData));
+
+    // 20->32->21
+    inputData.push_back(
+            makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+    vector<vector<int>> actual;
+    extractIntoVector(inputData, actual);
+    vector<int> expectedV1 = {20, 32, 73};
+    EXPECT_EQ(1, (int)actual.size());
+    EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, NoNeedToMerge) {
+    vector<shared_ptr<LogEvent>> inputData;
+
+    // 32
+    inputData.push_back(makeNonUidAtomLogEvent(timestamp, isolatedNonAdditiveData));
+
+    // 22
+    inputData.push_back(makeNonUidAtomLogEvent(timestamp, hostNonAdditiveData));
+
+    sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+    mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
+
+    EXPECT_EQ(2, (int)inputData.size());
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
index c4407f4..6dc041f 100644
--- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -42,7 +42,7 @@
     size_t size;
     uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
 
-    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/-1, /*pid=*/-1);
+    std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
     logEvent->parseBuffer(buf, size);
     AStatsEvent_release(statsEvent);
     return logEvent;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index b882678..d55996c 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -13,16 +13,19 @@
 // limitations under the License.
 
 #include "src/metrics/CountMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <math.h>
 #include <stdio.h>
+
 #include <vector>
 
+#include "metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
 using namespace testing;
 using android::sp;
 using std::set;
@@ -37,366 +40,392 @@
 
 const ConfigKey kConfigKey(0, 12345);
 
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(CountMetricProducerTest, TestFirstBucket) {
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
-//                                      600 * NS_PER_SEC + NS_PER_SEC / 2);
-//    EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(10, countProducer.mCurrentBucketNum);
-//    EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
-//}
-//
-//TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-//    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-//    int tagId = 1;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.init();
-//    LogEvent event2(tagId, bucketStartTimeNs + 2);
-//    event2.init();
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      bucketStartTimeNs, bucketStartTimeNs);
-//
-//    // 2 events in bucket 1.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-//    // Flushes at event #2.
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-//    // Flushes.
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-//    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                countProducer.mPastBuckets.end());
-//    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(2LL, buckets[0].mCount);
-//
-//    // 1 matched event happens in bucket 2.
-//    LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-//    event3.init();
-//
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-//    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                countProducer.mPastBuckets.end());
-//    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
-//    EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
-//    EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
-//    EXPECT_EQ(1LL, bucketInfo2.mCount);
-//
-//    // nothing happens in bucket 3. we should not record anything for bucket 3.
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-//    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                countProducer.mPastBuckets.end());
-//    const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(2UL, buckets3.size());
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_condition(StringToId("SCREEN_ON"));
-//
-//    LogEvent event1(1, bucketStartTimeNs + 1);
-//    event1.init();
-//
-//    LogEvent event2(1, bucketStartTimeNs + 10);
-//    event2.init();
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-//    CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
-//                                      bucketStartTimeNs);
-//
-//    countProducer.onConditionChanged(true, bucketStartTimeNs);
-//    countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-//    countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
-//    // Upon this match event, the matched event1 is flushed.
-//    countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-//    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                countProducer.mPastBuckets.end());
-//    {
-//        const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//        EXPECT_EQ(1UL, buckets.size());
-//        const auto& bucketInfo = buckets[0];
-//        EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-//        EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-//        EXPECT_EQ(1LL, bucketInfo.mCount);
-//    }
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-//    int tagId = 1;
-//    int conditionTagId = 2;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    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);
-//    event1.write("111");  // uid
-//    event1.init();
-//    ConditionKey key1;
-//    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
-//        {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-//    LogEvent event2(tagId, bucketStartTimeNs + 10);
-//    event2.write("222");  // uid
-//    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));
-//
-//    CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
-//                                      bucketStartTimeNs, bucketStartTimeNs);
-//
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-//    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                countProducer.mPastBuckets.end());
-//    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets.size());
-//    const auto& bucketInfo = buckets[0];
-//    EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-//    EXPECT_EQ(1LL, bucketInfo.mCount);
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//    int conditionTagId = 2;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    Alert alert;
-//    alert.set_num_buckets(3);
-//    alert.set_trigger_if_sum_gt(2);
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.write("111");  // uid
-//    event1.init();
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-//                                      bucketStartTimeNs, bucketStartTimeNs);
-//
-//    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-//    EXPECT_TRUE(anomalyTracker != nullptr);
-//
-//    // Bucket is flushed yet.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // App upgrade forces bucket flush.
-//    // Check that there's a past bucket and the bucket end is not adjusted.
-//    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((long long)bucketStartTimeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-//    EXPECT_EQ((long long)eventUpgradeTimeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-//    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//    // Anomaly tracker only contains full buckets.
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
-//    // Next event occurs in same bucket as partial bucket created.
-//    LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10);
-//    event2.write("222");  // uid
-//    event2.init();
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-//    // Third event in following bucket.
-//    LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10);
-//    event3.write("333");  // uid
-//    event3.init();
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-//    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//    int conditionTagId = 2;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.write("111");  // uid
-//    event1.init();
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-//                                      bucketStartTimeNs, bucketStartTimeNs);
-//
-//    // Bucket is flushed yet.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-//    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-//    // App upgrade forces bucket flush.
-//    // Check that there's a past bucket and the bucket end is not adjusted.
-//    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)bucketStartTimeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-//    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//
-//    // Next event occurs in same bucket as partial bucket created.
-//    LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10);
-//    event2.write("222");  // uid
-//    event2.init();
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-//    // Third event in following bucket.
-//    LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10);
-//    event3.write("333");  // uid
-//    event3.init();
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-//    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ((int64_t)eventUpgradeTimeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-//              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
-//}
-//
-//TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    Alert alert;
-//    alert.set_id(11);
-//    alert.set_metric_id(1);
-//    alert.set_trigger_if_sum_gt(2);
-//    alert.set_num_buckets(2);
-//    const int32_t refPeriodSec = 1;
-//    alert.set_refractory_period_secs(refPeriodSec);
-//
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-//    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-//
-//    CountMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-//                                      bucketStartTimeNs, bucketStartTimeNs);
-//
-//    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-//    int tagId = 1;
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.init();
-//    LogEvent event2(tagId, bucketStartTimeNs + 2);
-//    event2.init();
-//    LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    event3.init();
-//    LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
-//    event4.init();
-//    LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
-//    event5.init();
-//    LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
-//    event6.init();
-//    LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
-//    event7.init();
-//
-//    // Two events in bucket #0.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-//    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-//    EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    // One event in bucket #2. No alarm as bucket #0 is trashed out.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-//    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-//    EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-//    // Two events in bucket #3.
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
-//    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-//    EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
-//    // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//            std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-//    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
-//    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-//    EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
-//    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-//            std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//}
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeString(statsEvent, uid.c_str());
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+
+}  // namespace
+
+TEST(CountMetricProducerTest, TestFirstBucket) {
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
+                                      600 * NS_PER_SEC + NS_PER_SEC / 2);
+    EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(10, countProducer.mCurrentBucketNum);
+    EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
+}
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+    int tagId = 1;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      bucketStartTimeNs, bucketStartTimeNs);
+
+    // 2 events in bucket 1.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    // Flushes at event #2.
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    // Flushes.
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                countProducer.mPastBuckets.end());
+    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(2LL, buckets[0].mCount);
+
+    // 1 matched event happens in bucket 2.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                countProducer.mPastBuckets.end());
+    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
+    EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+    EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+    EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+    // nothing happens in bucket 3. we should not record anything for bucket 3.
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                countProducer.mPastBuckets.end());
+    const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+    CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
+                                      bucketStartTimeNs);
+
+    countProducer.onConditionChanged(true, bucketStartTimeNs);
+
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
+    countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+
+    // Upon this match event, the matched event1 is flushed.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
+    countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                countProducer.mPastBuckets.end());
+
+    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    const auto& bucketInfo = buckets[0];
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+    EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    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, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
+
+    ConditionKey key1;
+    key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+            getMockedDimensionKey(conditionTagId, 2, "111")};
+
+    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));
+
+    CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
+                                      bucketStartTimeNs, bucketStartTimeNs);
+
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+    EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                countProducer.mPastBuckets.end());
+    const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    const auto& bucketInfo = buckets[0];
+    EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+    EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
+    sp<AlarmMonitor> alarmMonitor;
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    Alert alert;
+    alert.set_num_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+                                      bucketStartTimeNs, bucketStartTimeNs);
+
+    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    // Bucket is flushed yet.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // App upgrade forces bucket flush.
+    // Check that there's a past bucket and the bucket end is not adjusted.
+    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((long long)bucketStartTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    EXPECT_EQ((long long)eventUpgradeTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    // Anomaly tracker only contains full buckets.
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
+    // Next event occurs in same bucket as partial bucket created.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+    // Third event in following bucket.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+
+    int tagId = 1;
+    int conditionTagId = 2;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+                                      bucketStartTimeNs, bucketStartTimeNs);
+
+    // Bucket is flushed yet.
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+    // App upgrade forces bucket flush.
+    // Check that there's a past bucket and the bucket end is not adjusted.
+    countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)bucketStartTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+
+    // Next event occurs in same bucket as partial bucket created.
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+    EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+    // Third event in following bucket.
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ((int64_t)eventUpgradeTimeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
+}
+
+TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
+    sp<AlarmMonitor> alarmMonitor;
+    Alert alert;
+    alert.set_id(11);
+    alert.set_metric_id(1);
+    alert.set_trigger_if_sum_gt(2);
+    alert.set_num_buckets(2);
+    const int32_t refPeriodSec = 1;
+    alert.set_refractory_period_secs(refPeriodSec);
+
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+    int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+
+    CountMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      bucketStartTimeNs, bucketStartTimeNs);
+
+    sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
+    LogEvent event5(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
+    LogEvent event6(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
+    LogEvent event7(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
+
+    // Two events in bucket #0.
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+    EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    // One event in bucket #2. No alarm as bucket #0 is trashed out.
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+    EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+    // Two events in bucket #3.
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
+    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+    EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
+    // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+    countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
+    EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+    EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
+    EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+              std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+}
 
 TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
     CountMetric metric;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 6661374..6143dc0 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -13,17 +13,20 @@
 // limitations under the License.
 
 #include "src/metrics/DurationMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "src/condition/ConditionWizard.h"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <stdio.h>
+
 #include <set>
 #include <unordered_map>
 #include <vector>
 
+#include "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+
 using namespace android::os::statsd;
 using namespace testing;
 using android::sp;
@@ -39,6 +42,22 @@
 
 const ConfigKey kConfigKey(0, 12345);
 
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, atomId);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+    AStatsEvent_build(statsEvent);
+
+    size_t size;
+    uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+    logEvent->parseBuffer(buf, size);
+    AStatsEvent_release(statsEvent);
+}
+
+}  // namespace
+
 TEST(DurationMetricTrackerTest, TestFirstBucket) {
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     DurationMetric metric;
@@ -56,383 +75,386 @@
     EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
 }
 
-// TODO(b/149590301): Update these to use new socket schema.
-//TEST(DurationMetricTrackerTest, TestNoCondition) {
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//    int tagId = 1;
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.init();
-//    LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-//    event2.init();
-//
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-//    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                durationProducer.mPastBuckets.end());
-//    const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(2UL, buckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
-//    EXPECT_EQ(2LL, buckets[1].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//    int tagId = 1;
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.init();
-//    LogEvent event2(tagId, bucketStartTimeNs + 2);
-//    event2.init();
-//    LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-//    event3.init();
-//    LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-//    event4.init();
-//
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//    durationProducer.mCondition = ConditionState::kFalse;
-//
-//    EXPECT_FALSE(durationProducer.mCondition);
-//    EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-//    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-//    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-//                durationProducer.mPastBuckets.end());
-//    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets2.size());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-//    EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//    int tagId = 1;
-//    LogEvent event1(tagId, bucketStartTimeNs + 1);
-//    event1.init();
-//    LogEvent event2(tagId, bucketStartTimeNs + 2);
-//    event2.init();
-//    LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-//    event3.init();
-//    LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-//    event4.init();
-//
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
-//    EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-//    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-//    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets2.size());
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-//    EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
-//    /**
-//     * The duration starts from the first bucket, through the two partial buckets (10-70sec),
-//     * another bucket, and ends at the beginning of the next full bucket.
-//     * Expected buckets:
-//     *  - [10,25]: 14 secs
-//     *  - [25,70]: All 45 secs
-//     *  - [70,130]: All 60 secs
-//     *  - [130, 210]: Only 5 secs (event ended at 135sec)
-//     */
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-//    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    LogEvent start_event(tagId, startTimeNs);
-//    start_event.init();
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    std::vector<DurationBucket> buckets =
-//            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
-//    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-//    LogEvent end_event(tagId, endTimeNs);
-//    end_event.init();
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(3UL, buckets.size());
-//    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-//    EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
-//    /**
-//     * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
-//     *  - [10,70]: 59 secs
-//     *  - [70,75]: 5 sec
-//     *  - [75,130]: 55 secs
-//     */
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-//    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-//    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    LogEvent start_event(tagId, startTimeNs);
-//    start_event.init();
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    std::vector<DurationBucket> buckets =
-//            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-//    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
-//    EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
-//    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-//    LogEvent end_event(tagId, endTimeNs);
-//    end_event.init();
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(3UL, buckets.size());
-//    EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
-//    sp<AlarmMonitor> alarmMonitor;
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//    int64_t startTimeNs = bucketStartTimeNs + 1;
-//    int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//
-//    // Setup metric with alert.
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//    Alert alert;
-//    alert.set_num_buckets(3);
-//    alert.set_trigger_if_sum_gt(2);
-//
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
-//    EXPECT_TRUE(anomalyTracker != nullptr);
-//
-//    LogEvent start_event(tagId, startTimeNs);
-//    start_event.init();
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-//    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-//    LogEvent end_event(tagId, endTimeNs);
-//    end_event.init();
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//
-//    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
-//              anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//    int64_t startTimeNs = bucketStartTimeNs + 1;
-//    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-//    LogEvent event1(tagId, startTimeNs);
-//    event1.write("111");  // uid
-//    event1.init();
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    LogEvent start_event(tagId, startTimeNs);
-//    start_event.init();
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-//    LogEvent end_event(tagId, endTimeNs);
-//    end_event.init();
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-//    std::vector<DurationBucket> buckets =
-//            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets.size());
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
-//    int64_t bucketStartTimeNs = 10000000000;
-//    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-//    int64_t startTimeNs = bucketStartTimeNs + 1;
-//    int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
-//
-//    int tagId = 1;
-//
-//    DurationMetric metric;
-//    metric.set_id(1);
-//    metric.set_bucket(ONE_MINUTE);
-//    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-//    LogEvent event1(tagId, startTimeNs);
-//    event1.write("111");  // uid
-//    event1.init();
-//    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//    FieldMatcher dimensions;
-//    DurationMetricProducer durationProducer(
-//            kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-//            3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-//    LogEvent start_event(tagId, startTimeNs);
-//    start_event.init();
-//    durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    // Stop occurs in the same partial bucket as created for the app upgrade.
-//    LogEvent end_event(tagId, endTimeNs);
-//    end_event.init();
-//    durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-//    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-//    std::vector<DurationBucket> buckets =
-//            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-//    EXPECT_EQ(1UL, buckets.size());
-//    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
-//    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
-//    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
+TEST(DurationMetricTrackerTest, TestNoCondition) {
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                durationProducer.mPastBuckets.end());
+    const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(2UL, buckets.size());
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
+    EXPECT_EQ(2LL, buckets[1].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+    durationProducer.mCondition = ConditionState::kFalse;
+
+    EXPECT_FALSE(durationProducer.mCondition);
+    EXPECT_FALSE(durationProducer.isConditionSliced());
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+    EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+                durationProducer.mPastBuckets.end());
+    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets2.size());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+    EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+    LogEvent event3(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+    LogEvent event4(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
+    EXPECT_FALSE(durationProducer.isConditionSliced());
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+    durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+    const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets2.size());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+    EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
+    /**
+     * The duration starts from the first bucket, through the two partial buckets (10-70sec),
+     * another bucket, and ends at the beginning of the next full bucket.
+     * Expected buckets:
+     *  - [10,25]: 14 secs
+     *  - [25,70]: All 45 secs
+     *  - [70,130]: All 60 secs
+     *  - [130, 210]: Only 5 secs (event ended at 135sec)
+     */
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, startTimeNs, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, endTimeNs, tagId);
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(3UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+    EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
+    /**
+     * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
+     *  - [10,70]: 59 secs
+     *  - [70,75]: 5 sec
+     *  - [75,130]: 55 secs
+     */
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+    int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, startTimeNs, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, endTimeNs, tagId);
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
+    EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(3UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
+    sp<AlarmMonitor> alarmMonitor;
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    int64_t startTimeNs = bucketStartTimeNs + 1;
+    int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, startTimeNs, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, endTimeNs, tagId);
+
+    // Setup metric with alert.
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+    Alert alert;
+    alert.set_num_buckets(3);
+    alert.set_trigger_if_sum_gt(2);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
+    EXPECT_TRUE(anomalyTracker != nullptr);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
+              anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+    int64_t startTimeNs = bucketStartTimeNs + 1;
+    int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, startTimeNs, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, endTimeNs, tagId);
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+    int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+    int64_t startTimeNs = bucketStartTimeNs + 1;
+    int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
+
+    int tagId = 1;
+    LogEvent event1(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event1, startTimeNs, tagId);
+    LogEvent event2(/*uid=*/0, /*pid=*/0);
+    makeLogEvent(&event2, endTimeNs, tagId);
+
+    DurationMetric metric;
+    metric.set_id(1);
+    metric.set_bucket(ONE_MINUTE);
+    metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    FieldMatcher dimensions;
+    DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+                                            1 /* start index */, 2 /* stop index */,
+                                            3 /* stop_all index */, false /*nesting*/, wizard,
+                                            dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+    durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+    EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    // Stop occurs in the same partial bucket as created for the app upgrade.
+    durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+    EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+    durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+    std::vector<DurationBucket> buckets =
+            durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+    EXPECT_EQ(1UL, buckets.size());
+    EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
+    EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d416f13..e2eee03 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -410,40 +410,75 @@
     return dimensions;
 }
 
-// TODO(b/149590301): Update these helpers to use new socket schema.
-//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);
-//    EXPECT_TRUE(event->write(state));
-//    event->init();
-//    return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(
-//        android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-//    EXPECT_TRUE(event->write(BatterySaverModeStateChanged::ON));
-//    event->init();
-//    return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(
-//        android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-//    EXPECT_TRUE(event->write(BatterySaverModeStateChanged::OFF));
-//    event->init();
-//    return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-//    int level, uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
-//    EXPECT_TRUE(event->write(level));
-//    event->init();
-//    return event;
-//
-//}
-//
+std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
+        uint64_t timestampNs, const android::view::DisplayStateEnum state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    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> CreateBatterySaverOnEvent(uint64_t timestampNs) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
+    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> CreateBatterySaverOffEvent(uint64_t timestampNs) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
+    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> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_BRIGHTNESS_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, level);
+    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) {
@@ -470,121 +505,212 @@
 //            attributions, name, 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> CreateAcquireWakelockEvent(
-//        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-//        uint64_t timestampNs) {
-//    return CreateWakelockStateChangedEvent(
-//        attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs);
-//}
-//
-//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> CreateProcessLifeCycleStateChangedEvent(
-//    const int uid, const ProcessLifeCycleStateChanged::State state, uint64_t timestampNs) {
-//    auto logEvent = std::make_unique<LogEvent>(
-//        android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, timestampNs);
-//    logEvent->write(uid);
-//    logEvent->write("");
-//    logEvent->write(state);
-//    logEvent->init();
-//    return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampNs) {
-//    return CreateProcessLifeCycleStateChangedEvent(
-//        uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs);
-//    event->write(uid);
-//    event->write("eventType");
-//    event->write("processName");
-//    event->init();
-//    return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
-//    int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
-//    auto logEvent = std::make_unique<LogEvent>(
-//        android::util::ISOLATED_UID_CHANGED, timestampNs);
-//    logEvent->write(hostUid);
-//    logEvent->write(isolatedUid);
-//    logEvent->write(is_create);
-//    logEvent->init();
-//    return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-//        int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) {
-//    auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs);
-//    event->write(uid);
-//    event->write(state);
-//    event->init();
-//    return event;
-//}
+std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
+                                                          const vector<int>& attributionUids,
+                                                          const vector<string>& attributionTags,
+                                                          const string& wakelockName,
+                                                          const WakelockStateChanged::State state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::WAKELOCK_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_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
+    AStatsEvent_writeString(statsEvent, wakelockName.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(uint64_t timestampNs,
+                                                     const vector<int>& attributionUids,
+                                                     const vector<string>& attributionTags,
+                                                     const string& wakelockName) {
+    return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+                                           wakelockName, WakelockStateChanged::ACQUIRE);
+}
+
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs,
+                                                     const vector<int>& attributionUids,
+                                                     const vector<string>& attributionTags,
+                                                     const string& wakelockName) {
+    return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+                                           wakelockName, WakelockStateChanged::RELEASE);
+}
+
+std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
+        uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    AStatsEvent_writeString(statsEvent, "pkg_name");
+    AStatsEvent_writeString(statsEvent, "class_name");
+    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> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) {
+    return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+                                                     ActivityForegroundStateChanged::BACKGROUND);
+}
+
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) {
+    return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+                                                     ActivityForegroundStateChanged::FOREGROUND);
+}
+
+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, android::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> 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> CreateSyncEndEvent(uint64_t timestampNs,
+                                             const vector<int>& attributionUids,
+                                             const vector<string>& attributionTags,
+                                             const string& name) {
+    return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+                                       SyncStateChanged::OFF);
+}
+
+std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
+        uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    AStatsEvent_writeString(statsEvent, "");
+    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> CreateAppCrashEvent(uint64_t timestampNs, const int uid) {
+    return CreateProcessLifeCycleStateChangedEvent(timestampNs, uid,
+                                                   ProcessLifeCycleStateChanged::CRASHED);
+}
+
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::APP_CRASH_OCCURRED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    AStatsEvent_writeString(statsEvent, "eventType");
+    AStatsEvent_writeString(statsEvent, "processName");
+    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> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
+                                                        int isolatedUid, bool is_create) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::ISOLATED_UID_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, hostUid);
+    AStatsEvent_writeInt32(statsEvent, isolatedUid);
+    AStatsEvent_writeInt32(statsEvent, is_create);
+    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> CreateUidProcessStateChangedEvent(
+        uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) {
+    AStatsEvent* statsEvent = AStatsEvent_obtain();
+    AStatsEvent_setAtomId(statsEvent, android::util::UID_PROCESS_STATE_CHANGED);
+    AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+    AStatsEvent_writeInt32(statsEvent, uid);
+    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;
+}
 
 sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
                                               const StatsdConfig& config, const ConfigKey& key,
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index c8326ee..49163273 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -166,11 +166,10 @@
 
 // Create log event for screen state changed.
 std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-    const android::view::DisplayStateEnum state, uint64_t timestampNs);
+        uint64_t timestampNs, const android::view::DisplayStateEnum state);
 
 // Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-   int level, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level);
 
 // Create log event when scheduled job starts.
 std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
@@ -188,45 +187,42 @@
 std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs);
 
 // Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid);
 
 // Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid);
 
 // 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>& uids,
+                                               const vector<string>& tags, 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);
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs, const vector<int>& uids,
+                                             const vector<string>& tags, const string& name);
 
 // Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(
-    const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid);
 
 // Create log event for an app crash.
-std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid);
 
 // Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+                                                     const vector<string>& tags,
+                                                     const string& wakelockName);
 
 // Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
-        const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-        uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+                                                     const vector<string>& tags,
+                                                     const string& wakelockName);
 
 // 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> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int isolatedUid,
+                                                        int hostUid, bool is_create);
 
 // Create log event for uid process state change.
 std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-        int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs);
+        uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state);
 
 // Helper function to create an AttributionNodeInternal proto.
 AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index f613df2..eeb5d41 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -162,7 +162,7 @@
  * might also make sense inside of a single app if the access is forwarded between two features of
  * the app.
  *
- * <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the
+ * <p>An app can register an {@link OnOpNotedCallback} to get informed about what accesses the
  * system is tracking for it. As each runtime permission has an associated app-op this API is
  * particularly useful for an app that want to find unexpected private data accesses.
  */
@@ -206,16 +206,16 @@
 
     private static final Object sLock = new Object();
 
-    /** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
+    /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
     @GuardedBy("sLock")
-    private static @Nullable AppOpsCollector sNotedAppOpsCollector;
+    private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
 
     /**
      * Additional collector that collect accesses and forwards a few of them them via
      * {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
      */
-    private static AppOpsCollector sMessageCollector =
-            new AppOpsCollector() {
+    private static OnOpNotedCallback sMessageCollector =
+            new OnOpNotedCallback() {
                 @Override
                 public void onNoted(@NonNull SyncNotedAppOp op) {
                     reportStackTraceIfNeeded(op);
@@ -1060,9 +1060,12 @@
     /** @hide Access telephony call audio */
     public static final int OP_ACCESS_CALL_AUDIO = 96;
 
+    /** @hide Auto-revoke app permissions if app is unused for an extended period */
+    public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97;
+
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 97;
+    public static final int _NUM_OP = 98;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1357,6 +1360,11 @@
     @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
+    public static final String OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED =
+            "android:auto_revoke_permissions_if_unused";
+
     /** @hide Communicate cross-profile within the same profile group. */
     @SystemApi
     public static final String OPSTR_INTERACT_ACROSS_PROFILES = "android:interact_across_profiles";
@@ -1446,6 +1454,7 @@
             OP_INTERACT_ACROSS_PROFILES,
             OP_LOADER_USAGE_STATS,
             OP_ACCESS_CALL_AUDIO,
+            OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
     };
 
     /**
@@ -1554,6 +1563,7 @@
             OP_ACTIVATE_PLATFORM_VPN,           // ACTIVATE_PLATFORM_VPN
             OP_LOADER_USAGE_STATS,              // LOADER_USAGE_STATS
             OP_ACCESS_CALL_AUDIO,               // ACCESS_CALL_AUDIO
+            OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -1657,6 +1667,7 @@
             OPSTR_ACTIVATE_PLATFORM_VPN,
             OPSTR_LOADER_USAGE_STATS,
             OPSTR_ACCESS_CALL_AUDIO,
+            OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED,
     };
 
     /**
@@ -1761,6 +1772,7 @@
             "ACTIVATE_PLATFORM_VPN",
             "LOADER_USAGE_STATS",
             "ACCESS_CALL_AUDIO",
+            "AUTO_REVOKE_PERMISSIONS_IF_UNUSED",
     };
 
     /**
@@ -1866,6 +1878,7 @@
             null, // no permission for OP_ACTIVATE_PLATFORM_VPN
             android.Manifest.permission.LOADER_USAGE_STATS,
             Manifest.permission.ACCESS_CALL_AUDIO,
+            null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -1971,6 +1984,7 @@
             null, // ACTIVATE_PLATFORM_VPN
             null, // LOADER_USAGE_STATS
             null, // ACCESS_CALL_AUDIO
+            null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -2075,6 +2089,7 @@
             false, // ACTIVATE_PLATFORM_VPN
             false, // LOADER_USAGE_STATS
             false, // ACCESS_CALL_AUDIO
+            false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -2178,6 +2193,7 @@
             AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN
             AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS
             AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO
+            AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -2285,6 +2301,7 @@
             false, // ACTIVATE_PLATFORM_VPN
             false, // LOADER_USAGE_STATS
             false, // ACCESS_CALL_AUDIO
+            false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
     };
 
     /**
@@ -7783,8 +7800,8 @@
      */
     private void collectNotedOpForSelf(int op, @Nullable String featureId) {
         synchronized (sLock) {
-            if (sNotedAppOpsCollector != null) {
-                sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+            if (sOnOpNotedCallback != null) {
+                sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
             }
         }
         sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
@@ -7933,8 +7950,8 @@
                 synchronized (sLock) {
                     for (int code = notedAppOps.nextSetBit(0); code != -1;
                             code = notedAppOps.nextSetBit(code + 1)) {
-                        if (sNotedAppOpsCollector != null) {
-                            sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
+                        if (sOnOpNotedCallback != null) {
+                            sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
                         }
                     }
                 }
@@ -7947,33 +7964,45 @@
     }
 
     /**
-     * Register a new {@link AppOpsCollector}.
+     * Set a new {@link OnOpNotedCallback}.
      *
-     * <p>There can only ever be one collector per process. If there currently is a collector
-     * registered, it will be unregistered.
+     * <p>There can only ever be one collector per process. If there currently is another callback
+     * set, this will fail.
      *
-     * <p><b>Only appops related to dangerous permissions are collected.</b>
+     * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
+     * null} to unset
+     * @param callback listener to set, {@code null} to unset
      *
-     * @param collector The collector to set or {@code null} to unregister.
+     * @throws IllegalStateException If another callback is already registered
      */
-    public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+    public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
+            @Nullable OnOpNotedCallback callback) {
+        Preconditions.checkState((callback == null) == (asyncExecutor == null));
+
         synchronized (sLock) {
-            if (sNotedAppOpsCollector != null) {
+            if (callback == null) {
+                Preconditions.checkState(sOnOpNotedCallback != null,
+                        "No callback is currently registered");
+
                 try {
                     mService.stopWatchingAsyncNoted(mContext.getPackageName(),
-                            sNotedAppOpsCollector.mAsyncCb);
+                            sOnOpNotedCallback.mAsyncCb);
                 } catch (RemoteException e) {
                     e.rethrowFromSystemServer();
                 }
-            }
 
-            sNotedAppOpsCollector = collector;
+                sOnOpNotedCallback = null;
+            } else {
+                Preconditions.checkState(sOnOpNotedCallback == null,
+                        "Another callback is already registered");
 
-            if (sNotedAppOpsCollector != null) {
+                callback.mAsyncExecutor = asyncExecutor;
+                sOnOpNotedCallback = callback;
+
                 List<AsyncNotedAppOp> missedAsyncOps = null;
                 try {
                     mService.startWatchingAsyncNoted(mContext.getPackageName(),
-                            sNotedAppOpsCollector.mAsyncCb);
+                            sOnOpNotedCallback.mAsyncCb);
                     missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
                 } catch (RemoteException e) {
                     e.rethrowFromSystemServer();
@@ -7983,10 +8012,9 @@
                     int numMissedAsyncOps = missedAsyncOps.size();
                     for (int i = 0; i < numMissedAsyncOps; i++) {
                         final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
-                        if (sNotedAppOpsCollector != null) {
-                            sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
-                                    () -> sNotedAppOpsCollector.onAsyncNoted(
-                                            asyncNotedAppOp));
+                        if (sOnOpNotedCallback != null) {
+                            sOnOpNotedCallback.getAsyncNotedExecutor().execute(
+                                    () -> sOnOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
                         }
                     }
                 }
@@ -7994,27 +8022,50 @@
         }
     }
 
+    // TODO moltmann: Remove
     /**
-     * @return {@code true} iff the process currently is currently collecting noted appops.
+     * Will be removed before R ships, leave it just to not break apps immediately.
      *
-     * @see #setNotedAppOpsCollector(AppOpsCollector)
+     * @removed
      *
      * @hide
      */
-    public static boolean isCollectingNotedAppOps() {
-        return sNotedAppOpsCollector != null;
+    @SystemApi
+    @Deprecated
+    public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+        synchronized (sLock) {
+            if (collector != null) {
+                if (isListeningForOpNoted()) {
+                    setOnOpNotedCallback(null, null);
+                }
+                setOnOpNotedCallback(new HandlerExecutor(Handler.getMain()), collector);
+            } else if (sOnOpNotedCallback != null) {
+                setOnOpNotedCallback(null, null);
+            }
+        }
     }
 
     /**
-     * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the
-     * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
-     * one of the callback methods of this object is called.
+     * @return {@code true} iff the process currently is currently collecting noted appops.
      *
-     * <p><b>There will be a callback for all app-ops related to runtime permissions, but not
+     * @see #setOnOpNotedCallback
+     *
+     * @hide
+     */
+    public static boolean isListeningForOpNoted() {
+        return sOnOpNotedCallback != null;
+    }
+
+    /**
+     * Callback an app can {@link #setOnOpNotedCallback set} to monitor the app-ops the
+     * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
+     * one of a method of this object is called.
+     *
+     * <p><b>There will be a call for all app-ops related to runtime permissions, but not
      * necessarily for all other app-ops.
      *
      * <pre>
-     * setNotedAppOpsCollector(new AppOpsCollector() {
+     * setOnOpNotedCallback(getMainExecutor(), new OnOpNotedCallback() {
      *     ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>();
      *
      *     private synchronized void addAccess(String op, String accessLocation) {
@@ -8039,24 +8090,36 @@
      * });
      * </pre>
      *
-     * @see #setNotedAppOpsCollector
+     * @see #setOnOpNotedCallback
      */
-    public abstract static class AppOpsCollector {
+    public abstract static class OnOpNotedCallback {
+        private @NonNull Executor mAsyncExecutor;
+
         /** Callback registered with the system. This will receive the async notes ops */
         private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
             @Override
             public void opNoted(AsyncNotedAppOp op) {
                 Objects.requireNonNull(op);
 
-                getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+                long token = Binder.clearCallingIdentity();
+                try {
+                    getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             }
         };
 
+        // TODO moltmann: Remove
         /**
+         * Will be removed before R ships.
+         *
          * @return The executor for the system to use when calling {@link #onAsyncNoted}.
+         *
+         * @hide
          */
-        public @NonNull Executor getAsyncNotedExecutor() {
-            return new HandlerExecutor(Handler.getMain());
+        protected @NonNull Executor getAsyncNotedExecutor() {
+            return mAsyncExecutor;
         }
 
         /**
@@ -8066,7 +8129,7 @@
          * <p>Called on the calling thread before the API returns. This allows the app to e.g.
          * collect stack traces to figure out where the access came from.
          *
-         * @param op The op noted
+         * @param op op noted
          */
         public abstract void onNoted(@NonNull SyncNotedAppOp op);
 
@@ -8076,7 +8139,7 @@
          * <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the
          * API provider in a separate process, but by one in the app's own process.
          *
-         * @param op The op noted
+         * @param op op noted
          */
         public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
 
@@ -8088,14 +8151,30 @@
          * guaranteed. Due to how async calls work in Android this might even be delivered slightly
          * before the private data is delivered to the app.
          *
-         * <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
-         * of noted app-ops are buffered and then delivered as soon as a collector is registered.
+         * <p>If the app is not running or no {@link OnOpNotedCallback} is registered a small amount
+         * of noted app-ops are buffered and then delivered as soon as a listener is registered.
          *
-         * @param asyncOp The op noted
+         * @param asyncOp op noted
          */
         public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
     }
 
+    // TODO moltmann: Remove
+    /**
+     * Will be removed before R ships, leave it just to not break apps immediately.
+     *
+     * @removed
+     *
+     * @hide
+     */
+    @SystemApi
+    @Deprecated
+    public abstract static class AppOpsCollector extends OnOpNotedCallback {
+        public @NonNull Executor getAsyncNotedExecutor() {
+            return new HandlerExecutor(Handler.getMain());
+        }
+    };
+
     /**
      * Generate a stack trace used for noted app-ops logging.
      *
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 6b1afda..4d955db 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.CurrentTimeMillisLong;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -23,13 +24,15 @@
 
 import com.android.internal.annotations.Immutable;
 import com.android.internal.util.DataClass;
+import com.android.internal.util.Preconditions;
 
 /**
  * When an {@link AppOpsManager#noteOp(String, int, String, String, String) app-op is noted} and the
- * app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
- * needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
- * in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
- * server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
+ * app the app-op is noted for has a {@link AppOpsManager.OnOpNotedCallback} registered the
+ * note-event needs to be delivered to the callback. Usually this is done via an
+ * {@link SyncNotedAppOp}, but in some cases this is not possible. In this case an
+ * {@link AsyncNotedAppOp} is send to the system server and then forwarded to the
+ * {@link AppOpsManager.OnOpNotedCallback} in the app.
  */
 @Immutable
 @DataClass(genEqualsHashCode = true,
@@ -40,7 +43,7 @@
 @DataClass.Suppress({"getOpCode"})
 public final class AsyncNotedAppOp implements Parcelable {
     /** Op that was noted */
-    private final @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int mOpCode;
+    private final @IntRange(from = 0) int mOpCode;
 
     /** Uid that noted the op */
     private final @IntRange(from = 0) int mNotingUid;
@@ -52,7 +55,7 @@
     private final @NonNull String mMessage;
 
     /** Milliseconds since epoch when the op was noted */
-    private final @IntRange(from = 0) long mTime;
+    private final @CurrentTimeMillisLong long mTime;
 
     /**
      * @return Op that was noted.
@@ -61,9 +64,15 @@
         return AppOpsManager.opToPublicName(mOpCode);
     }
 
+    //TODO eugenesusla: support inlinable expressions in annotation params of @DataClass members to
+    // allow validating via @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1)
+    private void onConstructed() {
+        Preconditions.checkArgumentInRange(mOpCode, 0, AppOpsManager._NUM_OP - 1, "opCode");
+    }
 
 
-    // Code below generated by codegen v1.0.14.
+
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -93,16 +102,15 @@
      */
     @DataClass.Generated.Member
     public AsyncNotedAppOp(
-            @IntRange(from = 0, to = AppOpsManager._NUM_OP - 1) int opCode,
+            @IntRange(from = 0) int opCode,
             @IntRange(from = 0) int notingUid,
             @Nullable String featureId,
             @NonNull String message,
-            @IntRange(from = 0) long time) {
+            @CurrentTimeMillisLong long time) {
         this.mOpCode = opCode;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mOpCode,
-                "from", 0,
-                "to", AppOpsManager._NUM_OP - 1);
+                "from", 0);
         this.mNotingUid = notingUid;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
@@ -113,10 +121,9 @@
                 NonNull.class, null, mMessage);
         this.mTime = time;
         com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mTime,
-                "from", 0);
+                CurrentTimeMillisLong.class, null, mTime);
 
-        // onConstructed(); // You can define this method to get a callback
+        onConstructed();
     }
 
     /**
@@ -147,7 +154,7 @@
      * Milliseconds since epoch when the op was noted
      */
     @DataClass.Generated.Member
-    public @IntRange(from = 0) long getTime() {
+    public @CurrentTimeMillisLong long getTime() {
         return mTime;
     }
 
@@ -223,8 +230,7 @@
         this.mOpCode = opCode;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mOpCode,
-                "from", 0,
-                "to", AppOpsManager._NUM_OP - 1);
+                "from", 0);
         this.mNotingUid = notingUid;
         com.android.internal.util.AnnotationValidations.validate(
                 IntRange.class, null, mNotingUid,
@@ -235,10 +241,9 @@
                 NonNull.class, null, mMessage);
         this.mTime = time;
         com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mTime,
-                "from", 0);
+                CurrentTimeMillisLong.class, null, mTime);
 
-        // onConstructed(); // You can define this method to get a callback
+        onConstructed();
     }
 
     @DataClass.Generated.Member
@@ -256,10 +261,10 @@
     };
 
     @DataClass.Generated(
-            time = 1581728574427L,
-            codegenVersion = "1.0.14",
+            time = 1583866178330L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
-            inputSignatures = "private final @android.annotation.IntRange(from=0L, to=96L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+            inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate  void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 28b28da..145d513 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -37,13 +37,15 @@
 
     /**
      * Called whenever IActivityManager.startActivity is called on an activity that is already
-     * running in the pinned stack and the activity is not actually started, but the task is either
-     * brought to the front or a new Intent is delivered to it.
+     * running, but the task is either brought to the front or a new Intent is delivered to it.
      *
+     * @param task information about the task the activity was relaunched into
+     * @param homeVisible whether or not the home task is visible
      * @param clearedTask whether or not the launch activity also cleared the task as a part of
      * starting
      */
-    void onPinnedActivityRestartAttempt(boolean clearedTask);
+    void onActivityRestartAttempt(in ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask);
 
     /**
      * Called when we launched an activity that we forced to be resizable.
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index aa11b95..13b90ca 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -28,9 +28,9 @@
  * Description of an app-op that was noted for the current process.
  *
  * <p>This is either delivered after a
- * {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
+ * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
  * when the app
- * {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
+ * {@link AppOpsManager.OnOpNotedCallback#onSelfNoted(SyncNotedAppOp) notes an app-op for
  * itself}.
  */
 @Immutable
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index b892b8e..93772de 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.TaskSnapshot;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
@@ -53,7 +54,8 @@
 
     @Override
     @UnsupportedAppUsage
-    public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException {
+    public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask) throws RemoteException {
     }
 
     @Override
@@ -68,14 +70,14 @@
     }
 
     @Override
-    public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo,
+    public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
             int requestedDisplayId) throws RemoteException {
         onActivityLaunchOnSecondaryDisplayFailed();
     }
 
     /**
      * @deprecated see {@link
-     *         #onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo, int)}
+     *         #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)}
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -84,7 +86,7 @@
 
     @Override
     @UnsupportedAppUsage
-    public void onActivityLaunchOnSecondaryDisplayRerouted(ActivityManager.RunningTaskInfo taskInfo,
+    public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
             int requestedDisplayId) throws RemoteException {
     }
 
@@ -98,13 +100,13 @@
     }
 
     @Override
-    public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+    public void onTaskMovedToFront(RunningTaskInfo taskInfo)
             throws RemoteException {
         onTaskMovedToFront(taskInfo.taskId);
     }
 
     /**
-     * @deprecated see {@link #onTaskMovedToFront(ActivityManager.RunningTaskInfo)}
+     * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)}
      */
     @Deprecated
     @UnsupportedAppUsage
@@ -112,26 +114,26 @@
     }
 
     @Override
-    public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo)
+    public void onTaskRemovalStarted(RunningTaskInfo taskInfo)
             throws RemoteException {
         onTaskRemovalStarted(taskInfo.taskId);
     }
 
     /**
-     * @deprecated see {@link #onTaskRemovalStarted(ActivityManager.RunningTaskInfo)}
+     * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)}
      */
     @Deprecated
     public void onTaskRemovalStarted(int taskId) throws RemoteException {
     }
 
     @Override
-    public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
+    public void onTaskDescriptionChanged(RunningTaskInfo taskInfo)
             throws RemoteException {
         onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
     }
 
     /**
-     * @deprecated see {@link #onTaskDescriptionChanged(ActivityManager.RunningTaskInfo)}
+     * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)}
      */
     @Deprecated
     public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
@@ -166,7 +168,7 @@
     }
 
     @Override
-    public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
+    public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)
             throws RemoteException {
     }
 
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 5684562..878993e 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -60,7 +60,6 @@
         mWms = WindowManagerGlobal.getWindowManagerService();
         mToken = new WindowTokenClient();
 
-
         final ContextImpl contextImpl = createBaseWindowContext(base, mToken);
         attachBaseContext(contextImpl);
         contextImpl.setOuterContext(this);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index b219394..c532279 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8781,18 +8781,20 @@
     }
 
     /**
+     * This method is mostly deprecated.
+     * Most of the settings that still have an effect have dedicated setter methods or user
+     * restrictions. See individual settings for details.
+     * <p>
      * Called by device owner to update {@link android.provider.Settings.Global} settings.
      * Validation that the value of the setting is in the correct form for the setting type should
      * be performed by the caller.
      * <p>
      * The settings that can be updated with this method are:
      * <ul>
-     * <li>{@link android.provider.Settings.Global#ADB_ENABLED}</li>
-     * <li>{@link android.provider.Settings.Global#AUTO_TIME}</li>
-     * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE}</li>
-     * <li>{@link android.provider.Settings.Global#DATA_ROAMING}</li>
+     * <li>{@link android.provider.Settings.Global#ADB_ENABLED} : use
+     * {@link UserManager#DISALLOW_DEBUGGING_FEATURES} instead to restrict users from enabling
+     * debugging features and this setting to turn adb on.</li>
      * <li>{@link android.provider.Settings.Global#USB_MASS_STORAGE_ENABLED}</li>
-     * <li>{@link android.provider.Settings.Global#WIFI_SLEEP_POLICY}</li>
      * <li>{@link android.provider.Settings.Global#STAY_ON_WHILE_PLUGGED_IN} This setting is only
      * available from {@link android.os.Build.VERSION_CODES#M} onwards and can only be set if
      * {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
@@ -8800,6 +8802,16 @@
      * setting is only available from {@link android.os.Build.VERSION_CODES#M} onwards.</li>
      * </ul>
      * <p>
+     * The following settings used to be supported, but can be controlled in other ways:
+     * <ul>
+     * <li>{@link android.provider.Settings.Global#AUTO_TIME} : Use {@link #setAutoTime} and
+     * {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
+     * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE} : Use {@link #setAutoTimeZone}
+     * and {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
+     * <li>{@link android.provider.Settings.Global#DATA_ROAMING} : Use
+     * {@link UserManager#DISALLOW_DATA_ROAMING} instead.</li>
+     * </ul>
+     * <p>
      * Changing the following settings has no effect as of {@link android.os.Build.VERSION_CODES#M}:
      * <ul>
      * <li>{@link android.provider.Settings.Global#BLUETOOTH_ON}. Use
@@ -8811,6 +8823,7 @@
      * <li>{@link android.provider.Settings.Global#NETWORK_PREFERENCE}</li>
      * <li>{@link android.provider.Settings.Global#WIFI_ON}. Use
      * {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} instead.</li>
+     * <li>{@link android.provider.Settings.Global#WIFI_SLEEP_POLICY}. No longer has effect.</li>
      * </ul>
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -8989,6 +9002,11 @@
     }
 
     /**
+     * This method is mostly deprecated.
+     * Most of the settings that still have an effect have dedicated setter methods
+     * (e.g. {@link #setLocationEnabled}) or user restrictions.
+     * <p>
+     *
      * Called by profile or device owners to update {@link android.provider.Settings.Secure}
      * settings. Validation that the value of the setting is in the correct form for the setting
      * type should be performed by the caller.
@@ -9001,7 +9019,7 @@
      * <p>
      * A device owner can additionally update the following settings:
      * <ul>
-     * <li>{@link android.provider.Settings.Secure#LOCATION_MODE}</li>
+     * <li>{@link android.provider.Settings.Secure#LOCATION_MODE}, but see note below.</li>
      * </ul>
      *
      * <strong>Note: Starting from Android O, apps should no longer call this method with the
@@ -10355,19 +10373,23 @@
     }
 
     /**
-     * Indicates the entity that controls the device or profile owner. Two users/profiles are
-     * affiliated if the set of ids set by their device or profile owners intersect.
+     * Indicates the entity that controls the device. Two users are
+     * affiliated if the set of ids set by the device owner and the admin of the secondary user.
      *
-     * <p>A user/profile that is affiliated with the device owner user is considered to be
+     * <p>A user that is affiliated with the device owner user is considered to be
      * affiliated with the device.
      *
      * <p><strong>Note:</strong> Features that depend on user affiliation (such as security logging
-     * or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user or profile
+     * or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user
      * is created, until it becomes affiliated. Therefore it is recommended that the appropriate
-     * affiliation ids are set by its profile owner as soon as possible after the user/profile is
+     * affiliation ids are set by its owner as soon as possible after the user is
      * created.
+     * <p>
+     * Note: This method used to be available for affiliating device owner and profile
+     * owner. However, since Android 11, this combination is not possible. This method is now
+     * only useful for affiliating the primary user with managed secondary users.
      *
-     * @param admin Which profile or device owner this request is associated with.
+     * @param admin Which device owner, or owner of secondary user, this request is associated with.
      * @param ids A set of opaque non-empty affiliation ids.
      *
      * @throws IllegalArgumentException if {@code ids} is null or contains an empty string.
@@ -10399,10 +10421,10 @@
     }
 
     /**
-     * Returns whether this user/profile is affiliated with the device.
+     * Returns whether this user is affiliated with the device.
      * <p>
      * By definition, the user that the device owner runs on is always affiliated with the device.
-     * Any other user/profile is considered affiliated with the device if the set specified by its
+     * Any other user is considered affiliated with the device if the set specified by its
      * profile owner via {@link #setAffiliationIds} intersects with the device owner's.
      * @see #setAffiliationIds
      */
@@ -10706,14 +10728,18 @@
     }
 
     /**
-     * Called by a device owner to bind to a service from a profile owner or vice versa.
-     * See {@link #getBindDeviceAdminTargetUsers} for a definition of which
-     * device/profile owners are allowed to bind to services of another profile/device owner.
+     * Called by a device owner to bind to a service from a secondary managed user or vice versa.
+     * See {@link #getBindDeviceAdminTargetUsers} for the pre-requirements of a
+     * device owner to bind to services of another managed user.
      * <p>
      * The service must be protected by {@link android.Manifest.permission#BIND_DEVICE_ADMIN}.
      * Note that the {@link Context} used to obtain this
      * {@link DevicePolicyManager} instance via {@link Context#getSystemService(Class)} will be used
      * to bind to the {@link android.app.Service}.
+     * <p>
+     * Note: This method used to be available for communication between device owner and profile
+     * owner. However, since Android 11, this combination is not possible. This method is now
+     * only useful for communication between device owner and managed secondary users.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param serviceIntent Identifies the service to connect to.  The Intent must specify either an
@@ -10751,14 +10777,11 @@
     }
 
     /**
-     * Returns the list of target users that the calling device or profile owner can use when
-     * calling {@link #bindDeviceAdminServiceAsUser}.
+     * Returns the list of target users that the calling device owner or owner of secondary user
+     * can use when calling {@link #bindDeviceAdminServiceAsUser}.
      * <p>
-     * A device owner can bind to a service from a profile owner and vice versa, provided that:
-     * <ul>
-     * <li>Both belong to the same package name.
-     * <li>Both users are affiliated. See {@link #setAffiliationIds}.
-     * </ul>
+     * A device owner can bind to a service from a secondary managed user and vice versa, provided
+     * that both users are affiliated. See {@link #setAffiliationIds}.
      */
     public @NonNull List<UserHandle> getBindDeviceAdminTargetUsers(@NonNull ComponentName admin) {
         throwIfParentInstance("getBindDeviceAdminTargetUsers");
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index ccd8199..0d461f5 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -174,7 +174,7 @@
     public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
 
     /**
-     * An intent extra that contains one appWidgetId.
+     * An intent extra (int) that contains one appWidgetId.
      * <p>
      * The value will be an int that can be retrieved like this:
      * {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
@@ -182,7 +182,7 @@
     public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
 
     /**
-     * A bundle extra that contains whether or not an app has finished restoring a widget.
+     * A bundle extra (boolean) that contains whether or not an app has finished restoring a widget.
      * <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its
      * widgets followed by calling {@link #updateAppWidget} to update the views.
      *
@@ -192,22 +192,26 @@
 
 
     /**
-     * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
+     * A bundle extra (int) that contains the lower bound on the current width, in dips, of a
+     * widget instance.
      */
     public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
 
     /**
-     * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
+     * A bundle extra (int) that contains the lower bound on the current height, in dips, of a
+     * widget instance.
      */
     public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
 
     /**
-     * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+     * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+     * widget instance.
      */
     public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
 
     /**
-     * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+     * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+     * widget instance.
      */
     public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 66bfcbd..6ae68fc 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1229,10 +1229,11 @@
     public boolean factoryReset() {
         try {
             mServiceLock.readLock().lock();
-            if (mService != null) {
-                return mService.factoryReset();
+            if (mService != null && mService.factoryReset()
+                    && mManagerService != null && mManagerService.onFactoryReset()) {
+                return true;
             }
-            Log.e(TAG, "factoryReset(): IBluetooth Service is null");
+            Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
             SystemProperties.set("persist.bluetooth.factoryreset", "true");
         } catch (RemoteException e) {
             Log.e(TAG, "", e);
diff --git a/core/java/android/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 58bf874..8b48f4c 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -51,6 +51,7 @@
      * expression will be shown
      */
     @DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
+    @DataClass.MaySetToNull
     private @Nullable Pattern mNamePattern = null;
 
     /**
@@ -86,7 +87,7 @@
 
 
 
-    // Code below generated by codegen v1.0.11.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -273,7 +274,7 @@
          * If set, only devices with BSSID matching the given one will be shown
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setBssid(@Nullable MacAddress value) {
+        public @NonNull Builder setBssid(@NonNull MacAddress value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
             mBssid = value;
@@ -322,11 +323,15 @@
     }
 
     @DataClass.Generated(
-            time = 1571960300742L,
-            codegenVersion = "1.0.11",
+            time = 1582688421965L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/companion/WifiDeviceFilter.java",
-            inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
+            inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
     @Deprecated
     private void __metadata() {}
 
+
+    //@formatter:on
+    // End of generated code
+
 }
diff --git a/core/java/android/content/ApexContext.java b/core/java/android/content/ApexEnvironment.java
similarity index 80%
rename from core/java/android/content/ApexContext.java
rename to core/java/android/content/ApexEnvironment.java
index fe5cedc..b4cc3c2 100644
--- a/core/java/android/content/ApexContext.java
+++ b/core/java/android/content/ApexEnvironment.java
@@ -30,29 +30,29 @@
  * @hide
  */
 @SystemApi
-public class ApexContext {
+public class ApexEnvironment {
 
     private static final String APEX_DATA = "apexdata";
 
     /**
-     * Returns an ApexContext instance for the APEX with the provided {@code apexModuleName}.
+     * Returns an ApexEnvironment instance for the APEX with the provided {@code apexModuleName}.
      *
-     * <p>To preserve the safety and integrity of APEX modules, you must only obtain the ApexContext
-     * for your specific APEX, and you <em>must never</em> attempt to obtain an ApexContext for
-     * another APEX.  Any coordination between APEXs must be performed through well-defined
-     * interfaces; attempting to directly read or write raw files belonging to another APEX will
-     * violate the hermetic storage requirements placed upon each module.
+     * <p>To preserve the safety and integrity of APEX modules, you must only obtain the
+     * ApexEnvironment for your specific APEX, and you <em>must never</em> attempt to obtain an
+     * ApexEnvironment for another APEX.  Any coordination between APEXs must be performed through
+     * well-defined interfaces; attempting to directly read or write raw files belonging to another
+     * APEX will violate the hermetic storage requirements placed upon each module.
      */
     @NonNull
-    public static ApexContext getApexContext(@NonNull String apexModuleName) {
+    public static ApexEnvironment getApexEnvironment(@NonNull String apexModuleName) {
         Objects.requireNonNull(apexModuleName, "apexModuleName cannot be null");
         //TODO(b/141148175): Check that apexModuleName is an actual APEX name
-        return new ApexContext(apexModuleName);
+        return new ApexEnvironment(apexModuleName);
     }
 
     private final String mApexModuleName;
 
-    private ApexContext(String apexModuleName) {
+    private ApexEnvironment(String apexModuleName) {
         mApexModuleName = apexModuleName;
     }
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index ae786aa..31e1fc8 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
@@ -82,6 +83,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 import java.util.Random;
@@ -2669,6 +2671,15 @@
                 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
     }
 
+    /** @removed */
+    @Deprecated
+    public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+        final Collection<Uri> asCollection = new ArrayList<>();
+        uris.forEach(asCollection::add);
+        notifyChange(asCollection, observer, flags);
+    }
+
     /**
      * Notify registered observers that several rows have been updated.
      * <p>
@@ -2693,7 +2704,7 @@
      * @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
      *            {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
      */
-    public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+    public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
             @NotifyFlags int flags) {
         Objects.requireNonNull(uris, "uris");
 
@@ -4014,6 +4025,10 @@
      * @hide
      */
     @SystemApi
+    @TestApi
+    // We can't accept an already-opened FD here, since these methods are
+    // rewriting actual filesystem paths
+    @SuppressLint("StreamFiles")
     public static @NonNull Uri decodeFromFile(@NonNull File file) {
         return translateDeprecatedDataPath(file.getAbsolutePath());
     }
@@ -4030,6 +4045,10 @@
      * @hide
      */
     @SystemApi
+    @TestApi
+    // We can't accept an already-opened FD here, since these methods are
+    // rewriting actual filesystem paths
+    @SuppressLint("StreamFiles")
     public static @NonNull File encodeToFile(@NonNull Uri uri) {
         return new File(translateDeprecatedDataPath(uri));
     }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aba86e9..6cba327 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5128,7 +5128,7 @@
      * {@link android.os.incremental.IncrementalManager}.
      * @hide
      */
-    public static final String INCREMENTAL_SERVICE = "incremental_service";
+    public static final String INCREMENTAL_SERVICE = "incremental";
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve an
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6f6972..4bb7346 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1881,6 +1881,20 @@
             "android.intent.action.MANAGE_PERMISSIONS";
 
     /**
+     * Activity action: Launch UI to manage auto-revoke state.
+     * <p>
+     * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
+     * auto-revoke state will be reviewed (mandatory).
+     * </p>
+     * <p>
+     * Output: Nothing.
+     * </p>
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_AUTO_REVOKE_PERMISSIONS =
+            "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+
+    /**
      * Activity action: Launch UI to review permissions for an app.
      * The system uses this intent if permission review for apps not
      * supporting the new runtime permissions model is enabled. In
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 61128f2..f19ab01 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -274,6 +274,9 @@
      */
     public static final String SCHEME_HTTPS = "https";
 
+    /** The value to indicate a wildcard for incoming match arguments. */
+    private static final String WILDCARD = "*";
+
     private int mPriority;
     @UnsupportedAppUsage
     private int mOrder;
@@ -758,6 +761,17 @@
      * @return True if the action is listed in the filter.
      */
     public final boolean matchAction(String action) {
+        return matchAction(action, false);
+    }
+
+    /**
+     * Variant of {@link #matchAction(String)} that allows a wildcard for the provided action.
+     * @param wildcardSupported if true, will allow action to use wildcards
+     */
+    private boolean matchAction(String action, boolean wildcardSupported) {
+        if (wildcardSupported && !mActions.isEmpty() && WILDCARD.equals(action)) {
+            return true;
+        }
         return hasAction(action);
     }
 
@@ -1120,20 +1134,33 @@
          * {@link IntentFilter#MATCH_CATEGORY_HOST}.
          */
         public int match(Uri data) {
+            return match(data, false);
+        }
+
+        /**
+         * Variant of {@link #match(Uri)} that supports wildcards on the scheme, host and
+         * path of the provided {@link Uri}
+         *
+         * @param wildcardSupported if true, will allow parameters to use wildcards
+         * @hide
+         */
+        public int match(Uri data, boolean wildcardSupported) {
             String host = data.getHost();
             if (host == null) {
                 return NO_MATCH_DATA;
             }
             if (false) Log.v("IntentFilter",
                     "Match host " + host + ": " + mHost);
-            if (mWild) {
-                if (host.length() < mHost.length()) {
+            if (!wildcardSupported || !WILDCARD.equals(host)) {
+                if (mWild) {
+                    if (host.length() < mHost.length()) {
+                        return NO_MATCH_DATA;
+                    }
+                    host = host.substring(host.length() - mHost.length());
+                }
+                if (host.compareToIgnoreCase(mHost) != 0) {
                     return NO_MATCH_DATA;
                 }
-                host = host.substring(host.length()-mHost.length());
-            }
-            if (host.compareToIgnoreCase(mHost) != 0) {
-                return NO_MATCH_DATA;
             }
             if (mPort >= 0) {
                 if (mPort != data.getPort()) {
@@ -1207,9 +1234,21 @@
      *         filter.
      */
     public final boolean hasDataSchemeSpecificPart(String data) {
+        return hasDataSchemeSpecificPart(data, false);
+    }
+
+    /**
+     * Variant of {@link #hasDataSchemeSpecificPart(String)} that supports wildcards on the provided
+     * ssp.
+     * @param supportWildcards if true, will allow parameters to use wildcards
+     */
+    private boolean hasDataSchemeSpecificPart(String data, boolean supportWildcards) {
         if (mDataSchemeSpecificParts == null) {
             return false;
         }
+        if (supportWildcards && WILDCARD.equals(data) && mDataSchemeSpecificParts.size() > 0) {
+            return true;
+        }
         final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
         for (int i = 0; i < numDataSchemeSpecificParts; i++) {
             final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
@@ -1388,9 +1427,21 @@
      *         filter.
      */
     public final boolean hasDataPath(String data) {
+        return hasDataPath(data, false);
+    }
+
+    /**
+     * Variant of {@link #hasDataPath(String)} that supports wildcards on the provided scheme, host,
+     * and path.
+     * @param wildcardSupported if true, will allow parameters to use wildcards
+     */
+    private boolean hasDataPath(String data, boolean wildcardSupported) {
         if (mDataPaths == null) {
             return false;
         }
+        if (wildcardSupported && WILDCARD.equals(data)) {
+            return true;
+        }
         final int numDataPaths = mDataPaths.size();
         for (int i = 0; i < numDataPaths; i++) {
             final PatternMatcher pe = mDataPaths.get(i);
@@ -1435,13 +1486,24 @@
      * {@link #MATCH_CATEGORY_PORT}, {@link #NO_MATCH_DATA}.
      */
     public final int matchDataAuthority(Uri data) {
-        if (mDataAuthorities == null || data == null) {
+        return matchDataAuthority(data, false);
+    }
+
+    /**
+     * Variant of {@link #matchDataAuthority(Uri)} that allows wildcard matching of the provided
+     * authority.
+     *
+     * @param wildcardSupported if true, will allow parameters to use wildcards
+     * @hide
+     */
+    public final int matchDataAuthority(Uri data, boolean wildcardSupported) {
+        if (data == null || mDataAuthorities == null) {
             return NO_MATCH_DATA;
         }
         final int numDataAuthorities = mDataAuthorities.size();
         for (int i = 0; i < numDataAuthorities; i++) {
             final AuthorityEntry ae = mDataAuthorities.get(i);
-            int match = ae.match(data);
+            int match = ae.match(data, wildcardSupported);
             if (match >= 0) {
                 return match;
             }
@@ -1488,6 +1550,15 @@
      * @see #match
      */
     public final int matchData(String type, String scheme, Uri data) {
+        return matchData(type, scheme, data, false);
+    }
+
+    /**
+     * Variant of {@link #matchData(String, String, Uri)} that allows wildcard matching
+     * of the provided type, scheme, host and path parameters.
+     * @param wildcardSupported if true, will allow parameters to use wildcards
+     */
+    private int matchData(String type, String scheme, Uri data, boolean wildcardSupported) {
         final ArrayList<String> types = mDataTypes;
         final ArrayList<String> schemes = mDataSchemes;
 
@@ -1499,7 +1570,8 @@
         }
 
         if (schemes != null) {
-            if (schemes.contains(scheme != null ? scheme : "")) {
+            if (schemes.contains(scheme != null ? scheme : "")
+                    || wildcardSupported && WILDCARD.equals(scheme)) {
                 match = MATCH_CATEGORY_SCHEME;
             } else {
                 return NO_MATCH_DATA;
@@ -1507,19 +1579,19 @@
 
             final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
             if (schemeSpecificParts != null && data != null) {
-                match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
+                match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart(), wildcardSupported)
                         ? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
             }
             if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
                 // If there isn't any matching ssp, we need to match an authority.
                 final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
                 if (authorities != null) {
-                    int authMatch = matchDataAuthority(data);
+                    int authMatch = matchDataAuthority(data, wildcardSupported);
                     if (authMatch >= 0) {
                         final ArrayList<PatternMatcher> paths = mDataPaths;
                         if (paths == null) {
                             match = authMatch;
-                        } else if (hasDataPath(data.getPath())) {
+                        } else if (hasDataPath(data.getPath(), wildcardSupported)) {
                             match = MATCH_CATEGORY_PATH;
                         } else {
                             return NO_MATCH_DATA;
@@ -1541,7 +1613,8 @@
             // to force everyone to say they handle content: or file: URIs.
             if (scheme != null && !"".equals(scheme)
                     && !"content".equals(scheme)
-                    && !"file".equals(scheme)) {
+                    && !"file".equals(scheme)
+                    && !(wildcardSupported && WILDCARD.equals(scheme))) {
                 return NO_MATCH_DATA;
             }
         }
@@ -1701,13 +1774,23 @@
      */
     public final int match(String action, String type, String scheme,
             Uri data, Set<String> categories, String logTag) {
-        if (action != null && !matchAction(action)) {
+        return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/);
+    }
+
+    /**
+     * Variant of {@link #match(ContentResolver, Intent, boolean, String)} that supports wildcards
+     * in the action, type, scheme, host and path.
+     * @hide if true, will allow supported parameters to use wildcards to match this filter
+     */
+    public final int match(String action, String type, String scheme,
+            Uri data, Set<String> categories, String logTag, boolean supportWildcards) {
+        if (action != null && !matchAction(action, supportWildcards)) {
             if (false) Log.v(
                 logTag, "No matching action " + action + " for " + this);
             return NO_MATCH_ACTION;
         }
 
-        int dataMatch = matchData(type, scheme, data);
+        int dataMatch = matchData(type, scheme, data, supportWildcards);
         if (dataMatch < 0) {
             if (false) {
                 if (dataMatch == NO_MATCH_TYPE) {
diff --git a/core/java/android/content/pm/InstallationFile.java b/core/java/android/content/pm/InstallationFile.java
index edc04c9..de761ad 100644
--- a/core/java/android/content/pm/InstallationFile.java
+++ b/core/java/android/content/pm/InstallationFile.java
@@ -21,13 +21,25 @@
 import android.annotation.SystemApi;
 
 /**
- * Defines the properties of a file in an installation session.
+ * Definition of a file in a streaming installation session.
+ * You can use this class to retrieve the information of such a file, such as its name, size and
+ * metadata. These file attributes will be consistent with those used in:
+ * {@code PackageInstaller.Session#addFile}, when the file was first added into the session.
+ *
+ * WARNING: This is a system API to aid internal development.
+ * Use at your own risk. It will change or be removed without warning.
+ *
+ * @see android.content.pm.PackageInstaller.Session#addFile
  * @hide
  */
 @SystemApi
 public final class InstallationFile {
     private final @NonNull InstallationFileParcel mParcel;
 
+    /**
+     * Constructor, internal use only
+     * @hide
+     */
     public InstallationFile(@PackageInstaller.FileLocation int location, @NonNull String name,
             long lengthBytes, @Nullable byte[] metadata, @Nullable byte[] signature) {
         mParcel = new InstallationFileParcel();
@@ -38,22 +50,44 @@
         mParcel.signature = signature;
     }
 
+    /**
+     * Installation Location of this file. Can be one of the following three locations:
+     * <ul>
+     *     <li>(1) {@code PackageInstaller.LOCATION_DATA_APP}</li>
+     *     <li>(2) {@code PackageInstaller.LOCATION_MEDIA_OBB}</li>
+     *     <li>(3) {@code PackageInstaller.LOCATION_MEDIA_DATA}</li>
+     * </ul>
+     * @see android.content.pm.PackageInstaller
+     * @return Integer that denotes the installation location of the file.
+     */
     public @PackageInstaller.FileLocation int getLocation() {
         return mParcel.location;
     }
 
+    /**
+     * @return Name of the file.
+     */
     public @NonNull String getName() {
         return mParcel.name;
     }
 
+    /**
+     * @return File size in bytes.
+     */
     public long getLengthBytes() {
         return mParcel.size;
     }
 
+    /**
+     * @return File metadata as a byte array
+     */
     public @Nullable byte[] getMetadata() {
         return mParcel.metadata;
     }
 
+    /**
+     * @return File signature info as a byte array
+     */
     public @Nullable byte[] getSignature() {
         return mParcel.signature;
     }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 9b28cb5e8..7600a08 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2227,6 +2227,9 @@
      * <li>{@code VkPhysicalDeviceSamplerYcbcrConversionFeatures::samplerYcbcrConversion} is
      *     supported.</li>
      * </ul>
+     * A subset of devices that support Vulkan 1.1 do so via software emulation. For more
+     * information, see
+     * <a href="{@docRoot}ndk/guides/graphics/design-notes">Vulkan Design Guidelines</a>.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_VULKAN_HARDWARE_VERSION = "android.hardware.vulkan.version";
@@ -3400,29 +3403,12 @@
     public static final int FLAG_PERMISSION_ONE_TIME = 1 << 16;
 
     /**
-     * Permission flag: The permission is whitelisted to not be auto-revoked when app goes unused.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final int FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED = 1 << 17;
-
-    /**
-     * Permission flag: Whether {@link #FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED} state was set by
-     * user.
-     *
-     * @hide
-     */
-    @SystemApi
-    public static final int FLAG_PERMISSION_AUTO_REVOKE_USER_SET = 1 << 18;
-
-    /**
      * Permission flag: Whether permission was revoked by auto-revoke.
      *
      * @hide
      */
     @SystemApi
-    public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 20;
+    public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
 
     /**
      * Permission flags: Reserved for use by the permission controller.
@@ -3476,8 +3462,6 @@
             | FLAG_PERMISSION_GRANTED_BY_ROLE
             | FLAG_PERMISSION_REVOKED_COMPAT
             | FLAG_PERMISSION_ONE_TIME
-            | FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED
-            | FLAG_PERMISSION_AUTO_REVOKE_USER_SET
             | FLAG_PERMISSION_AUTO_REVOKED;
 
     /**
@@ -4302,8 +4286,6 @@
             FLAG_PERMISSION_GRANTED_BY_ROLE,
             FLAG_PERMISSION_REVOKED_COMPAT,
             FLAG_PERMISSION_ONE_TIME,
-            FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED,
-            FLAG_PERMISSION_AUTO_REVOKE_USER_SET,
             FLAG_PERMISSION_AUTO_REVOKED
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -7471,8 +7453,6 @@
             case FLAG_PERMISSION_GRANTED_BY_ROLE: return "GRANTED_BY_ROLE";
             case FLAG_PERMISSION_REVOKED_COMPAT: return "REVOKED_COMPAT";
             case FLAG_PERMISSION_ONE_TIME: return "ONE_TIME";
-            case FLAG_PERMISSION_AUTO_REVOKE_IF_UNUSED: return "AUTO_REVOKE_IF_UNUSED";
-            case FLAG_PERMISSION_AUTO_REVOKE_USER_SET: return "AUTO_REVOKE_USER_SET";
             case FLAG_PERMISSION_AUTO_REVOKED: return "AUTO_REVOKED";
             default: return Integer.toString(flag);
         }
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index ede264d..578d53b 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -19,6 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentResolver.NotifyFlags;
 import android.net.Uri;
@@ -26,12 +29,26 @@
 import android.os.UserHandle;
 
 import java.util.Arrays;
+import java.util.Collection;
 
 /**
  * Receives call backs for changes to content.
  * Must be implemented by objects which are added to a {@link ContentObservable}.
  */
 public abstract class ContentObserver {
+    /**
+     * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
+     * public API overload {@link #onChange(boolean, Uri, int)} that delivers a
+     * {@code int flags} argument.
+     * <p>
+     * Some apps may be relying on a previous hidden API that delivered a
+     * {@code int userId} argument, and this change is used to control delivery
+     * of the new {@code int flags} argument in its place.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
+    private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
+
     private final Object mLock = new Object();
     private Transport mTransport; // guarded by mLock
 
@@ -164,16 +181,26 @@
      * @param uris The Uris of the changed content.
      * @param flags Flags indicating details about this change.
      */
-    public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags) {
+    public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+            @NotifyFlags int flags) {
         for (Uri uri : uris) {
             onChange(selfChange, uri, flags);
         }
     }
 
     /** @hide */
-    public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags,
-            @UserIdInt int userId) {
-        onChange(selfChange, uris, flags);
+    public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+            @NotifyFlags int flags, @UserIdInt int userId) {
+        // There are dozens of people relying on the hidden API inside the
+        // system UID, so hard-code the old behavior for all of them; for
+        // everyone else we gate based on a specific change
+        if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS)
+                || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
+            // Deliver userId through argument to preserve hidden API behavior
+            onChange(selfChange, uris, userId);
+        } else {
+            onChange(selfChange, uris, flags);
+        }
     }
 
     /**
@@ -186,7 +213,7 @@
      *
      * @deprecated Callers should migrate towards using a richer overload that
      *             provides more details about the change, such as
-     *             {@link #dispatchChange(boolean, Iterable, int)}.
+     *             {@link #dispatchChange(boolean, Collection, int)}.
      */
     @Deprecated
     public final void dispatchChange(boolean selfChange) {
@@ -206,7 +233,7 @@
      * @param uri The Uri of the changed content.
      */
     public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
-        dispatchChange(selfChange, Arrays.asList(uri), 0, UserHandle.getCallingUserId());
+        dispatchChange(selfChange, uri, 0);
     }
 
     /**
@@ -224,7 +251,7 @@
      */
     public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
             @NotifyFlags int flags) {
-        dispatchChange(selfChange, Arrays.asList(uri), flags, UserHandle.getCallingUserId());
+        dispatchChange(selfChange, Arrays.asList(uri), flags);
     }
 
     /**
@@ -240,13 +267,13 @@
      * @param uris The Uri of the changed content.
      * @param flags Flags indicating details about this change.
      */
-    public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+    public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
             @NotifyFlags int flags) {
         dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
     }
 
     /** @hide */
-    public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+    public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
             @NotifyFlags int flags, @UserIdInt int userId) {
         if (mHandler == null) {
             onChange(selfChange, uris, flags, userId);
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 1855dd2..ce86807 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -20,10 +20,12 @@
 import android.annotation.UserIdInt;
 import android.content.ContentResolver.NotifyFlags;
 import android.net.Uri;
-import android.os.*;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
 
 import java.util.ArrayList;
-
+import java.util.Collection;
 
 /**
  * Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -81,7 +83,7 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+        public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
                 @NotifyFlags int flags, @UserIdInt int userId) {
             // Since we deliver changes from the most-specific to least-specific
             // overloads, we only need to redirect from the most-specific local
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 85ef4a3..a091f84 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -846,6 +846,33 @@
                 @NonNull String physicalCameraId) {
             // default empty implementation
         }
+
+        /**
+         * A camera device has been opened by an application.
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the new camera.
+         * @param packageId The package Id of the application opening the camera.
+         *
+         * @see #onCameraClosed
+         */
+        /** @hide */
+        public void onCameraOpened(@NonNull String cameraId, @NonNull String packageId) {
+            // default empty implementation
+        }
+
+        /**
+         * A previously-opened camera has been closed.
+         *
+         * <p>The default implementation of this method does nothing.</p>
+         *
+         * @param cameraId The unique identifier of the closed camera.
+         */
+        /** @hide */
+        public void onCameraClosed(@NonNull String cameraId) {
+            // default empty implementation
+        }
     }
 
     /**
@@ -1276,6 +1303,12 @@
                 }
                 @Override
                 public void onCameraAccessPrioritiesChanged() {
+                }
+                @Override
+                public void onCameraOpened(String id, String clientPackageId) {
+                }
+                @Override
+                public void onCameraClosed(String id) {
                 }};
 
             String[] cameraIds = null;
@@ -1503,6 +1536,38 @@
             }
         }
 
+        private void postSingleCameraOpenedUpdate(final AvailabilityCallback callback,
+                final Executor executor, final String id, final String packageId) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                executor.execute(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            callback.onCameraOpened(id, packageId);
+                        }
+                    });
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        private void postSingleCameraClosedUpdate(final AvailabilityCallback callback,
+                final Executor executor, final String id) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                executor.execute(
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            callback.onCameraClosed(id);
+                        }
+                    });
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
         private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
                 final String id, final String physicalId, final int status) {
             if (isAvailable(status)) {
@@ -1846,6 +1911,32 @@
             }
         }
 
+        @Override
+        public void onCameraOpened(String cameraId, String clientPackageId) {
+            synchronized (mLock) {
+                final int callbackCount = mCallbackMap.size();
+                for (int i = 0; i < callbackCount; i++) {
+                    Executor executor = mCallbackMap.valueAt(i);
+                    final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+                    postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId);
+                }
+            }
+        }
+
+        @Override
+        public void onCameraClosed(String cameraId) {
+            synchronized (mLock) {
+                final int callbackCount = mCallbackMap.size();
+                for (int i = 0; i < callbackCount; i++) {
+                    Executor executor = mCallbackMap.valueAt(i);
+                    final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+                    postSingleCameraClosedUpdate(callback, executor, cameraId);
+                }
+            }
+        }
+
         /**
          * Try to connect to camera service after some delay if any client registered camera
          * availability callback or torch status callback.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 2a71da8..9145142 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -129,10 +129,6 @@
             super(mac);
         }
 
-        public CryptoObject(@NonNull IdentityCredential credential) {
-            super(credential);
-        }
-
         /**
          * Get {@link Signature} object.
          * @return {@link Signature} object or null if this doesn't contain one.
@@ -160,8 +156,9 @@
         /**
          * Get {@link IdentityCredential} object.
          * @return {@link IdentityCredential} object or null if this doesn't contain one.
+         * @hide
          */
-        public @Nullable IdentityCredential getIdentityCredential() {
+        public IdentityCredential getIdentityCredential() {
             return super.getIdentityCredential();
         }
     }
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index c5cb803..e90b57c 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -37,7 +37,8 @@
     /**
      * Creates a new light with the given data.
      *
-     * @hide */
+     * @hide
+     */
     public Light(int id, int ordinal, int type) {
         mId = id;
         mOrdinal = ordinal;
@@ -76,8 +77,24 @@
                 }
             };
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof Light) {
+            Light light = (Light) obj;
+            return mId == light.mId && mOrdinal == light.mOrdinal && mType == light.mType;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
+    }
+
     /**
      * Returns the id of the light.
+     *
+     * <p>This is an opaque value used as a unique identifier for the light.
      */
     public int getId() {
         return mId;
@@ -86,11 +103,9 @@
     /**
      * Returns the ordinal of the light.
      *
-     * <p>This represents the physical order of the lights on the device. The exact values are
-     * device-dependent, but for example, if there are lights in a row, sorting the Light objects
-     * by ordinal should match the order in which they appear on the device. If the device has
-     * 4 lights, the ordinals could be [1, 2, 3, 4] or [0, 10, 20, 30] or any other values that
-     * have the same sort order.
+     * <p>This is a sort key that represents the physical order of lights on the device with the
+     * same type. In the case of multiple lights arranged in a line, for example, the ordinals
+     * could be [1, 2, 3, 4], or [0, 10, 20, 30], or any other values that have the same sort order.
      */
     public int getOrdinal() {
         return mOrdinal;
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 1bc051b..8cd2312 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -161,7 +161,7 @@
          * @param request the settings for lights that should change
          */
         @RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
-        public void setLights(@NonNull LightsRequest request) {
+        public void requestLights(@NonNull LightsRequest request) {
             Preconditions.checkNotNull(request);
             if (!mClosed) {
                 try {
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index a36da4c..5c4fc67 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -86,7 +86,7 @@
          * Create a LightsRequest object used to override lights on the device.
          *
          * <p>The generated {@link LightsRequest} should be used in
-         * {@link LightsManager.Session#setLights(LightsLightsRequest).
+         * {@link LightsManager.Session#requestLights(LightsLightsRequest).
          */
         public @NonNull LightsRequest build() {
             return new LightsRequest(mChanges);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 38ef814..fc6954f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -53,7 +53,6 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ServiceSpecificException;
-import android.os.SystemClock;
 import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
@@ -808,7 +807,7 @@
 
     private INetworkManagementService mNMService;
     private INetworkPolicyManager mNPManager;
-    private TetheringManager mTetheringManager;
+    private final TetheringManager mTetheringManager;
 
     /**
      * Tests if a given integer represents a valid network type.
@@ -2274,6 +2273,7 @@
     public ConnectivityManager(Context context, IConnectivityManager service) {
         mContext = Preconditions.checkNotNull(context, "missing context");
         mService = Preconditions.checkNotNull(service, "missing IConnectivityManager");
+        mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
         sInstance = this;
     }
 
@@ -2347,28 +2347,6 @@
         return getInstanceOrNull();
     }
 
-    private static final int TETHERING_TIMEOUT_MS = 60_000;
-    private final Object mTetheringLock = new Object();
-
-    private TetheringManager getTetheringManager() {
-        synchronized (mTetheringLock) {
-            if (mTetheringManager != null) {
-                return mTetheringManager;
-            }
-            final long before = System.currentTimeMillis();
-            while ((mTetheringManager = (TetheringManager) mContext.getSystemService(
-                    Context.TETHERING_SERVICE)) == null) {
-                if (System.currentTimeMillis() - before > TETHERING_TIMEOUT_MS) {
-                    Log.e(TAG, "Timeout waiting tethering service not ready yet");
-                    throw new IllegalStateException("No tethering service yet");
-                }
-                SystemClock.sleep(100);
-            }
-
-            return mTetheringManager;
-        }
-    }
-
     /**
      * Get the set of tetherable, available interfaces.  This list is limited by
      * device configuration and current interface existence.
@@ -2382,7 +2360,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetherableIfaces() {
-        return getTetheringManager().getTetherableIfaces();
+        return mTetheringManager.getTetherableIfaces();
     }
 
     /**
@@ -2397,7 +2375,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetheredIfaces() {
-        return getTetheringManager().getTetheredIfaces();
+        return mTetheringManager.getTetheredIfaces();
     }
 
     /**
@@ -2418,7 +2396,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetheringErroredIfaces() {
-        return getTetheringManager().getTetheringErroredIfaces();
+        return mTetheringManager.getTetheringErroredIfaces();
     }
 
     /**
@@ -2462,7 +2440,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public int tether(String iface) {
-        return getTetheringManager().tether(iface);
+        return mTetheringManager.tether(iface);
     }
 
     /**
@@ -2486,7 +2464,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public int untether(String iface) {
-        return getTetheringManager().untether(iface);
+        return mTetheringManager.untether(iface);
     }
 
     /**
@@ -2512,7 +2490,7 @@
     @RequiresPermission(anyOf = {android.Manifest.permission.TETHER_PRIVILEGED,
             android.Manifest.permission.WRITE_SETTINGS})
     public boolean isTetheringSupported() {
-        return getTetheringManager().isTetheringSupported();
+        return mTetheringManager.isTetheringSupported();
     }
 
     /**
@@ -2605,7 +2583,7 @@
         final TetheringRequest request = new TetheringRequest.Builder(type)
                 .setSilentProvisioning(!showProvisioningUi).build();
 
-        getTetheringManager().startTethering(request, executor, tetheringCallback);
+        mTetheringManager.startTethering(request, executor, tetheringCallback);
     }
 
     /**
@@ -2624,7 +2602,7 @@
     @Deprecated
     @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
     public void stopTethering(int type) {
-        getTetheringManager().stopTethering(type);
+        mTetheringManager.stopTethering(type);
     }
 
     /**
@@ -2682,7 +2660,7 @@
 
         synchronized (mTetheringEventCallbacks) {
             mTetheringEventCallbacks.put(callback, tetherCallback);
-            getTetheringManager().registerTetheringEventCallback(executor, tetherCallback);
+            mTetheringManager.registerTetheringEventCallback(executor, tetherCallback);
         }
     }
 
@@ -2704,7 +2682,7 @@
         synchronized (mTetheringEventCallbacks) {
             final TetheringEventCallback tetherCallback =
                     mTetheringEventCallbacks.remove(callback);
-            getTetheringManager().unregisterTetheringEventCallback(tetherCallback);
+            mTetheringManager.unregisterTetheringEventCallback(tetherCallback);
         }
     }
 
@@ -2724,7 +2702,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetherableUsbRegexs() {
-        return getTetheringManager().getTetherableUsbRegexs();
+        return mTetheringManager.getTetherableUsbRegexs();
     }
 
     /**
@@ -2742,7 +2720,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetherableWifiRegexs() {
-        return getTetheringManager().getTetherableWifiRegexs();
+        return mTetheringManager.getTetherableWifiRegexs();
     }
 
     /**
@@ -2761,7 +2739,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public String[] getTetherableBluetoothRegexs() {
-        return getTetheringManager().getTetherableBluetoothRegexs();
+        return mTetheringManager.getTetherableBluetoothRegexs();
     }
 
     /**
@@ -2785,7 +2763,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public int setUsbTethering(boolean enable) {
-        return getTetheringManager().setUsbTethering(enable);
+        return mTetheringManager.setUsbTethering(enable);
     }
 
     /**
@@ -2902,7 +2880,7 @@
     @UnsupportedAppUsage
     @Deprecated
     public int getLastTetherError(String iface) {
-        return getTetheringManager().getLastTetherError(iface);
+        return mTetheringManager.getLastTetherError(iface);
     }
 
     /** @hide */
@@ -2973,7 +2951,7 @@
             }
         };
 
-        getTetheringManager().requestLatestTetheringEntitlementResult(type, wrappedListener,
+        mTetheringManager.requestLatestTetheringEntitlementResult(type, wrappedListener,
                     showEntitlementUi);
     }
 
@@ -4469,7 +4447,7 @@
     public void factoryReset() {
         try {
             mService.factoryReset();
-            getTetheringManager().stopAllTethering();
+            mTetheringManager.stopAllTethering();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
index a3899b7..83b5f63 100644
--- a/core/java/android/net/EthernetManager.java
+++ b/core/java/android/net/EthernetManager.java
@@ -17,6 +17,7 @@
 package android.net;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -28,6 +29,7 @@
 
 import java.util.ArrayList;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
 /**
  * A class representing the IP configuration of the Ethernet network.
@@ -247,19 +249,24 @@
      * interface, the existing interface will be used.
      * @param callback A callback to be called once the request has been fulfilled.
      */
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+    })
     @NonNull
-    public TetheredInterfaceRequest requestTetheredInterface(
-            @NonNull TetheredInterfaceCallback callback) {
+    public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor,
+            @NonNull final TetheredInterfaceCallback callback) {
         Objects.requireNonNull(callback, "Callback must be non-null");
+        Objects.requireNonNull(executor, "Executor must be non-null");
         final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() {
             @Override
             public void onAvailable(String iface) {
-                callback.onAvailable(iface);
+                executor.execute(() -> callback.onAvailable(iface));
             }
 
             @Override
             public void onUnavailable() {
-                callback.onUnavailable();
+                executor.execute(() -> callback.onUnavailable());
             }
         };
 
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7cc569a..fef353f 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -126,7 +126,7 @@
     /**
      * Sent by the NetworkAgent to ConnectivityService to pass the current
      * network score.
-     * obj = network score Integer
+     * arg1 = network score int
      * @hide
      */
     public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
@@ -650,18 +650,7 @@
         if (score < 0) {
             throw new IllegalArgumentException("Score must be >= 0");
         }
-        final NetworkScore ns = new NetworkScore();
-        ns.putIntExtension(NetworkScore.LEGACY_SCORE, score);
-        updateScore(ns);
-    }
-
-    /**
-     * Must be called by the agent when it has a new {@link NetworkScore} for this network.
-     * @param ns the new score.
-     * @hide TODO: unhide the NetworkScore class, and rename to sendNetworkScore.
-     */
-    public void updateScore(@NonNull NetworkScore ns) {
-        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
+        queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score, 0);
     }
 
     /**
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
deleted file mode 100644
index 13f2994..0000000
--- a/core/java/android/net/NetworkScore.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * Object representing the quality of a network as perceived by the user.
- *
- * A NetworkScore object represents the characteristics of a network that affects how good the
- * network is considered for a particular use.
- * @hide
- */
-public final class NetworkScore implements Parcelable {
-
-    // The key of bundle which is used to get the legacy network score of NetworkAgentInfo.
-    // TODO: Remove this when the transition to NetworkScore is over.
-    public static final String LEGACY_SCORE = "LEGACY_SCORE";
-    @NonNull
-    private final Bundle mExtensions;
-
-    public NetworkScore() {
-        mExtensions = new Bundle();
-    }
-
-    public NetworkScore(@NonNull NetworkScore source) {
-        mExtensions = new Bundle(source.mExtensions);
-    }
-
-    /**
-     * Put the value of parcelable inside the bundle by key.
-     */
-    public void putExtension(@Nullable String key, @Nullable Parcelable value) {
-        mExtensions.putParcelable(key, value);
-    }
-
-    /**
-     * Put the value of int inside the bundle by key.
-     */
-    public void putIntExtension(@Nullable String key, int value) {
-        mExtensions.putInt(key, value);
-    }
-
-    /**
-     * Get the value of non primitive type by key.
-     */
-    public <T extends Parcelable> T getExtension(@Nullable String key) {
-        return mExtensions.getParcelable(key);
-    }
-
-    /**
-     * Get the value of int by key.
-     */
-    public int getIntExtension(@Nullable String key) {
-        return mExtensions.getInt(key);
-    }
-
-    /**
-     * Remove the entry by given key.
-     */
-    public void removeExtension(@Nullable String key) {
-        mExtensions.remove(key);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        synchronized (this) {
-            dest.writeBundle(mExtensions);
-        }
-    }
-
-    public static final @NonNull Creator<NetworkScore> CREATOR = new Creator<NetworkScore>() {
-        @Override
-        public NetworkScore createFromParcel(@NonNull Parcel in) {
-            return new NetworkScore(in);
-        }
-
-        @Override
-        public NetworkScore[] newArray(int size) {
-            return new NetworkScore[size];
-        }
-    };
-
-    private NetworkScore(@NonNull Parcel in) {
-        mExtensions = in.readBundle();
-    }
-
-    // TODO: Modify this method once new fields are added into this class.
-    @Override
-    public boolean equals(@Nullable Object obj) {
-        if (!(obj instanceof NetworkScore)) {
-            return false;
-        }
-        final NetworkScore other = (NetworkScore) obj;
-        return bundlesEqual(mExtensions, other.mExtensions);
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 29;
-        for (String key : mExtensions.keySet()) {
-            final Object value = mExtensions.get(key);
-            // The key may be null, so call Objects.hash() is safer.
-            result += 31 * value.hashCode() + 37 * Objects.hash(key);
-        }
-        return result;
-    }
-
-    // mExtensions won't be null since the constructor will create it.
-    private boolean bundlesEqual(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
-        if (bundle1 == bundle2) {
-            return true;
-        }
-
-        // This is unlikely but it's fine to add this clause here.
-        if (null == bundle1 || null == bundle2) {
-            return false;
-        }
-
-        if (bundle1.size() != bundle2.size()) {
-            return false;
-        }
-
-        for (String key : bundle1.keySet()) {
-            final Object value1 = bundle1.get(key);
-            final Object value2 = bundle2.get(key);
-            if (!Objects.equals(value1, value2)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /** Convert to a string */
-    public String toString() {
-        return "NetworkScore[" + mExtensions.toString() + "]";
-    }
-}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index fe7c7c9..c889ee6 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -248,6 +248,27 @@
         }
     }
 
+    static ThreadLocal<Boolean> sWarnOnBlockingOnCurrentThread =
+            ThreadLocal.withInitial(() -> sWarnOnBlocking);
+
+    /**
+     * Allow blocking calls for the current thread.  See {@link #allowBlocking}.
+     *
+     * @hide
+     */
+    public static void allowBlockingForCurrentThread() {
+        sWarnOnBlockingOnCurrentThread.set(false);
+    }
+
+    /**
+     * Reset the current thread to the default blocking behavior.  See {@link #defaultBlocking}.
+     *
+     * @hide
+     */
+    public static void defaultBlockingForCurrentThread() {
+        sWarnOnBlockingOnCurrentThread.set(sWarnOnBlocking);
+    }
+
     /**
      * Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null.
      */
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index be307ab..20e5f24 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -479,16 +479,21 @@
     public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
         Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
 
-        if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
+        if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)
+                && Binder.sWarnOnBlockingOnCurrentThread.get()) {
+
             // For now, avoid spamming the log by disabling after we've logged
             // about this interface at least once
             mWarnOnBlocking = false;
+
             if (Build.IS_USERDEBUG) {
                 // Log this as a WTF on userdebug builds.
-                Log.wtf(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+                Log.wtf(Binder.TAG,
+                        "Outgoing transactions from this process must be FLAG_ONEWAY",
                         new Throwable());
             } else {
-                Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
+                Log.w(Binder.TAG,
+                        "Outgoing transactions from this process must be FLAG_ONEWAY",
                         new Throwable());
             }
         }
@@ -521,7 +526,7 @@
         final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
                 AppOpsManager.pauseNotedAppOpsCollection();
 
-        if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
+        if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
             flags |= FLAG_COLLECT_NOTED_APP_OPS;
         }
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 21a1e0f..f2fb5b2 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -39,6 +39,7 @@
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Provides access to environment variables.
@@ -1253,6 +1254,50 @@
                 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
     }
 
+    /**
+     * Returns whether the calling app has All Files Access on the primary shared/external storage
+     * media.
+     * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+     * enough to gain the access.
+     * <p>To request access, use
+     * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+     */
+    public static boolean isExternalStorageManager() {
+        final File externalDir = sCurrentUser.getExternalDirs()[0];
+        return isExternalStorageManager(externalDir);
+    }
+
+    /**
+     * Returns whether the calling app has All Files Access at the given {@code path}
+     * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+     * enough to gain the access.
+     * <p>To request access, use
+     * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+     */
+    public static boolean isExternalStorageManager(@NonNull File path) {
+        final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
+        String packageName = Objects.requireNonNull(context.getPackageName());
+        int uid = context.getApplicationInfo().uid;
+
+        final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+        final int opMode =
+                appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
+
+        switch (opMode) {
+            case AppOpsManager.MODE_DEFAULT:
+                return PackageManager.PERMISSION_GRANTED
+                        == context.checkPermission(
+                                Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
+            case AppOpsManager.MODE_ALLOWED:
+                return true;
+            case AppOpsManager.MODE_ERRORED:
+            case AppOpsManager.MODE_IGNORED:
+                return false;
+            default:
+                throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
+        }
+    }
+
     static File getDirectory(String variableName, String defaultPath) {
         String path = System.getenv(variableName);
         return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 47f2461..a10a456 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ContentInterface;
 import android.content.ContentProvider;
@@ -1303,6 +1304,7 @@
      * {@hide}
      */
     @SystemApi
+    @TestApi
     public static @NonNull Uri setManageMode(@NonNull Uri uri) {
         Preconditions.checkNotNull(uri, "uri can not be null");
         return uri.buildUpon().appendQueryParameter(PARAM_MANAGE, "true").build();
@@ -1314,6 +1316,7 @@
      * {@hide}
      */
     @SystemApi
+    @TestApi
     public static boolean isManageMode(@NonNull Uri uri) {
         Preconditions.checkNotNull(uri, "uri can not be null");
         return uri.getBooleanQueryParameter(PARAM_MANAGE, false);
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 97f7533..03b38ab 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -3734,7 +3735,6 @@
          * @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
          */
         @Deprecated
-        @SystemApi
         public static final String BEARER_BITMASK = "bearer_bitmask";
 
         /**
@@ -3784,7 +3784,6 @@
          * <p>Type: INTEGER</p>
          *@hide
          */
-        @SystemApi
         public static final String PROFILE_ID = "profile_id";
 
         /**
@@ -3985,7 +3984,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static final String SKIP_464XLAT = "skip_464xlat";
 
         /**
@@ -3994,7 +3992,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static final int SKIP_464XLAT_DEFAULT = -1;
 
         /**
@@ -4003,7 +4000,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static final int SKIP_464XLAT_DISABLE = 0;
 
         /**
@@ -4012,7 +4008,6 @@
          *
          * @hide
          */
-        @SystemApi
         public static final int SKIP_464XLAT_ENABLE = 1;
 
 
@@ -4036,6 +4031,7 @@
          * @hide
          */
         @ChangeId
+        @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.Q)
         public static final long APN_READING_PERMISSION_CHANGE_ID = 124107808L;
     }
 
@@ -4390,6 +4386,7 @@
          * Indicates that whether the message has been broadcasted to the application.
          * <P>Type: BOOLEAN</P>
          */
+        // TODO: deprecate this in S.
         public static final String MESSAGE_BROADCASTED = "message_broadcasted";
 
         /**
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index e8e1223..06b5fa0 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -89,7 +89,7 @@
     private final @Nullable int[] mCancelIds;
     private final boolean mSupportsInlineSuggestions;
     // TODO(b/149240554): revert back to use ParceledListSlice after the bug is resolved.
-    private final @Nullable ArrayList<InlinePresentation> mInlineActions;
+    private final @Nullable ArrayList<InlineAction> mInlineActions;
 
     private FillResponse(@NonNull Builder builder) {
         mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
@@ -213,7 +213,7 @@
     }
 
     /** @hide */
-    public @Nullable List<InlinePresentation> getInlineActions() {
+    public @Nullable List<InlineAction> getInlineActions() {
         return mInlineActions;
     }
 
@@ -239,7 +239,7 @@
         private UserData mUserData;
         private int[] mCancelIds;
         private boolean mSupportsInlineSuggestions;
-        private ArrayList<InlinePresentation> mInlineActions;
+        private ArrayList<InlineAction> mInlineActions;
 
         /**
          * Triggers a custom UI before before autofilling the screen with any data set in this
@@ -656,15 +656,12 @@
         }
 
         /**
-         * Adds a new {@link InlinePresentation} to this response representing an action UI.
-         *
-         * <p> For example, the UI can be associated with an intent which can open an activity for
-         * the user to manage the Autofill provider settings.
+         * Adds a new {@link InlineAction} to this response representing an action UI.
          *
          * @return This builder.
          */
         @NonNull
-        public Builder addInlineAction(@NonNull InlinePresentation inlineAction) {
+        public Builder addInlineAction(@NonNull InlineAction inlineAction) {
             throwIfDestroyed();
             throwIfAuthenticationCalled();
             if (mInlineActions == null) {
@@ -881,10 +878,10 @@
             final int[] cancelIds = parcel.createIntArray();
             builder.setPresentationCancelIds(cancelIds);
 
-            final List<InlinePresentation> inlineActions = parcel.createTypedArrayList(
-                    InlinePresentation.CREATOR);
+            final List<InlineAction> inlineActions = parcel.createTypedArrayList(
+                    InlineAction.CREATOR);
             if (inlineActions != null) {
-                for (InlinePresentation inlineAction : inlineActions) {
+                for (InlineAction inlineAction : inlineActions) {
                     builder.addInlineAction(inlineAction);
                 }
             }
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/core/java/android/service/autofill/InlineAction.aidl
similarity index 71%
copy from wifi/java/android/net/wifi/IScoreChangeCallback.aidl
copy to core/java/android/service/autofill/InlineAction.aidl
index d691f41..7f85118 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/core/java/android/service/autofill/InlineAction.aidl
@@ -14,16 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi;
+package android.service.autofill;
 
-/**
- * Interface for Wi-Fi score callback.
- *
- * @hide
- */
-oneway interface IScoreChangeCallback
-{
-    void onScoreChange(int sessionId, int score);
-
-    void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
-}
+parcelable InlineAction;
diff --git a/core/java/android/service/autofill/InlineAction.java b/core/java/android/service/autofill/InlineAction.java
new file mode 100644
index 0000000..17c4b33
--- /dev/null
+++ b/core/java/android/service/autofill/InlineAction.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.autofill;
+
+import android.annotation.NonNull;
+import android.content.IntentSender;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents an inline action as part of the autofill/augmented autofill response.
+ *
+ * <p> It includes both the action intent and the UI presentation. For example, the UI can be
+ * associated with an intent which can open an activity for the user to manage the Autofill provider
+ * settings.
+ */
+@DataClass(
+        genToString = true,
+        genHiddenConstDefs = true,
+        genEqualsHashCode = true)
+public final class InlineAction implements Parcelable {
+
+    /**
+     * Representation of the inline action.
+     */
+    private final @NonNull InlinePresentation mInlinePresentation;
+
+    /**
+     * The associated intent which will be triggered when the action is selected. It will only be
+     * called by the OS.
+     */
+    private final @NonNull IntentSender mAction;
+
+
+
+    // Code below generated by codegen v1.0.15.
+    //
+    // DO NOT MODIFY!
+    // CHECKSTYLE:OFF Generated code
+    //
+    // To regenerate run:
+    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/autofill/InlineAction.java
+    //
+    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+    //   Settings > Editor > Code Style > Formatter Control
+    //@formatter:off
+
+
+    /**
+     * Creates a new InlineAction.
+     *
+     * @param inlinePresentation
+     *   Representation of the inline action.
+     * @param action
+     *   The associated intent which will be triggered when the action is selected. It will only be
+     *   invoked by the OS.
+     */
+    @DataClass.Generated.Member
+    public InlineAction(
+            @NonNull InlinePresentation inlinePresentation,
+            @NonNull IntentSender action) {
+        this.mInlinePresentation = inlinePresentation;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mInlinePresentation);
+        this.mAction = action;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAction);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    /**
+     * Representation of the inline action.
+     */
+    @DataClass.Generated.Member
+    public @NonNull InlinePresentation getInlinePresentation() {
+        return mInlinePresentation;
+    }
+
+    /**
+     * The associated intent which will be triggered when the action is selected. It will only be
+     * invoked by the OS.
+     */
+    @DataClass.Generated.Member
+    public @NonNull IntentSender getAction() {
+        return mAction;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public String toString() {
+        // You can override field toString logic by defining methods like:
+        // String fieldNameToString() { ... }
+
+        return "InlineAction { " +
+                "inlinePresentation = " + mInlinePresentation + ", " +
+                "action = " + mAction +
+        " }";
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@android.annotation.Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(InlineAction other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        InlineAction that = (InlineAction) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && java.util.Objects.equals(mInlinePresentation, that.mInlinePresentation)
+                && java.util.Objects.equals(mAction, that.mAction);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + java.util.Objects.hashCode(mInlinePresentation);
+        _hash = 31 * _hash + java.util.Objects.hashCode(mAction);
+        return _hash;
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+        // You can override field parcelling by defining methods like:
+        // void parcelFieldName(Parcel dest, int flags) { ... }
+
+        dest.writeTypedObject(mInlinePresentation, flags);
+        dest.writeTypedObject(mAction, flags);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int describeContents() { return 0; }
+
+    /** @hide */
+    @SuppressWarnings({"unchecked", "RedundantCast"})
+    @DataClass.Generated.Member
+    /* package-private */ InlineAction(@NonNull android.os.Parcel in) {
+        // You can override field unparcelling by defining methods like:
+        // static FieldType unparcelFieldName(Parcel in) { ... }
+
+        InlinePresentation inlinePresentation = (InlinePresentation) in.readTypedObject(InlinePresentation.CREATOR);
+        IntentSender action = (IntentSender) in.readTypedObject(IntentSender.CREATOR);
+
+        this.mInlinePresentation = inlinePresentation;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mInlinePresentation);
+        this.mAction = action;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mAction);
+
+        // onConstructed(); // You can define this method to get a callback
+    }
+
+    @DataClass.Generated.Member
+    public static final @NonNull Parcelable.Creator<InlineAction> CREATOR
+            = new Parcelable.Creator<InlineAction>() {
+        @Override
+        public InlineAction[] newArray(int size) {
+            return new InlineAction[size];
+        }
+
+        @Override
+        public InlineAction createFromParcel(@NonNull android.os.Parcel in) {
+            return new InlineAction(in);
+        }
+    };
+
+    @DataClass.Generated(
+            time = 1583798182424L,
+            codegenVersion = "1.0.15",
+            sourceFile = "frameworks/base/core/java/android/service/autofill/InlineAction.java",
+            inputSignatures = "private final @android.annotation.NonNull android.service.autofill.InlinePresentation mInlinePresentation\nprivate final @android.annotation.NonNull android.content.IntentSender mAction\nclass InlineAction extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstDefs=true, genEqualsHashCode=true)")
+    @Deprecated
+    private void __metadata() {}
+
+
+    //@formatter:on
+    // End of generated code
+
+}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index fe792b1..ed27dd5 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -40,7 +40,7 @@
 import android.os.SystemClock;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillEventHistory;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
 import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
 import android.util.Log;
 import android.util.Pair;
@@ -559,7 +559,7 @@
         }
 
         void reportResult(@Nullable List<Dataset> inlineSuggestionsData,
-                @Nullable List<InlinePresentation> inlineActions) {
+                @Nullable List<InlineAction> inlineActions) {
             try {
                 mCallback.onSuccess(inlineSuggestionsData, inlineActions);
             } catch (RemoteException e) {
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index b7fdf5a..f564b3b 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -21,7 +21,7 @@
 import android.annotation.TestApi;
 import android.os.Bundle;
 import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
 
 import com.android.internal.util.DataClass;
 
@@ -53,11 +53,10 @@
     private @Nullable List<Dataset> mInlineSuggestions;
 
     /**
-     * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
-     * inline actions are provided.
+     * Defaults to null if no inline actions are provided.
      */
     @DataClass.PluralOf("inlineAction")
-    private @Nullable List<InlinePresentation> mInlineActions;
+    private @Nullable List<InlineAction> mInlineActions;
 
     /**
      * The client state that {@link AugmentedAutofillService} implementation can put anything in to
@@ -74,7 +73,7 @@
         return null;
     }
 
-    private static List<InlinePresentation> defaultInlineActions() {
+    private static List<InlineAction> defaultInlineActions() {
         return null;
     }
 
@@ -86,12 +85,12 @@
     /** @hide */
     abstract static class BaseBuilder {
         abstract FillResponse.Builder addInlineSuggestion(@NonNull Dataset value);
-        abstract FillResponse.Builder addInlineAction(@NonNull InlinePresentation value);
+        abstract FillResponse.Builder addInlineAction(@NonNull InlineAction value);
     }
 
 
 
-    // Code below generated by codegen v1.0.14.
+    // Code below generated by codegen v1.0.15.
     //
     // DO NOT MODIFY!
     // CHECKSTYLE:OFF Generated code
@@ -108,7 +107,7 @@
     /* package-private */ FillResponse(
             @Nullable FillWindow fillWindow,
             @Nullable List<Dataset> inlineSuggestions,
-            @Nullable List<InlinePresentation> inlineActions,
+            @Nullable List<InlineAction> inlineActions,
             @Nullable Bundle clientState) {
         this.mFillWindow = fillWindow;
         this.mInlineSuggestions = inlineSuggestions;
@@ -140,13 +139,12 @@
     }
 
     /**
-     * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
-     * inline actions are provided.
+     * Defaults to null if no inline actions are provided.
      *
      * @hide
      */
     @DataClass.Generated.Member
-    public @Nullable List<InlinePresentation> getInlineActions() {
+    public @Nullable List<InlineAction> getInlineActions() {
         return mInlineActions;
     }
 
@@ -171,7 +169,7 @@
 
         private @Nullable FillWindow mFillWindow;
         private @Nullable List<Dataset> mInlineSuggestions;
-        private @Nullable List<InlinePresentation> mInlineActions;
+        private @Nullable List<InlineAction> mInlineActions;
         private @Nullable Bundle mClientState;
 
         private long mBuilderFieldsSet = 0L;
@@ -183,7 +181,7 @@
          * The {@link FillWindow} used to display the Autofill UI.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setFillWindow(@Nullable FillWindow value) {
+        public @NonNull Builder setFillWindow(@NonNull FillWindow value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x1;
             mFillWindow = value;
@@ -195,7 +193,7 @@
          * inline suggestions are available from the service.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setInlineSuggestions(@Nullable List<Dataset> value) {
+        public @NonNull Builder setInlineSuggestions(@NonNull List<Dataset> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x2;
             mInlineSuggestions = value;
@@ -212,11 +210,10 @@
         }
 
         /**
-         * The {@link InlinePresentation}s representing the inline actions. Defaults to null if no
-         * inline actions are provided.
+         * Defaults to null if no inline actions are provided.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setInlineActions(@Nullable List<InlinePresentation> value) {
+        public @NonNull Builder setInlineActions(@NonNull List<InlineAction> value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x4;
             mInlineActions = value;
@@ -226,7 +223,7 @@
         /** @see #setInlineActions */
         @DataClass.Generated.Member
         @Override
-        @NonNull FillResponse.Builder addInlineAction(@NonNull InlinePresentation value) {
+        @NonNull FillResponse.Builder addInlineAction(@NonNull InlineAction value) {
             if (mInlineActions == null) setInlineActions(new ArrayList<>());
             mInlineActions.add(value);
             return this;
@@ -238,7 +235,7 @@
          * {@link AugmentedAutofillService#getFillEventHistory()}.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setClientState(@Nullable Bundle value) {
+        public @NonNull Builder setClientState(@NonNull Bundle value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x8;
             mClientState = value;
@@ -279,10 +276,10 @@
     }
 
     @DataClass.Generated(
-            time = 1582682935951L,
-            codegenVersion = "1.0.14",
+            time = 1583793032373L,
+            codegenVersion = "1.0.15",
             sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java",
-            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlinePresentation> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  java.util.List<android.service.autofill.InlinePresentation> defaultInlineActions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlinePresentation)\nclass BaseBuilder extends java.lang.Object implements []")
+            inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineAction\") @android.annotation.Nullable java.util.List<android.service.autofill.InlineAction> mInlineActions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static  android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static  java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static  java.util.List<android.service.autofill.InlineAction> defaultInlineActions()\nprivate static  android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nabstract  android.service.autofill.augmented.FillResponse.Builder addInlineAction(android.service.autofill.InlineAction)\nclass BaseBuilder extends java.lang.Object implements []")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index bf0adcd..545dab2 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -20,7 +20,7 @@
 import android.os.ICancellationSignal;
 
 import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
 
 import java.util.List;
 
@@ -32,7 +32,7 @@
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
     void onSuccess(in @nullable List<Dataset> inlineSuggestionsData,
-                   in @nullable List<InlinePresentation> inlineActions);
+                   in @nullable List<InlineAction> inlineActions);
     boolean isCompleted();
     void cancel();
 }
diff --git a/core/java/android/service/contentcapture/DataShareReadAdapter.java b/core/java/android/service/contentcapture/DataShareReadAdapter.java
index a481ec8..8cd9eea 100644
--- a/core/java/android/service/contentcapture/DataShareReadAdapter.java
+++ b/core/java/android/service/contentcapture/DataShareReadAdapter.java
@@ -20,6 +20,7 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.os.ParcelFileDescriptor;
+import android.view.contentcapture.ContentCaptureManager.DataShareError;
 
 /**
  * Adapter class to be used for the Content Capture Service app to propagate the status of the
@@ -46,5 +47,5 @@
      * these 2 events is not defined, and it's important that the service treats end of stream
      * correctly in this situation.
      **/
-    void onError(int errorCode);
+    void onError(@DataShareError int errorCode);
 }
diff --git a/core/java/android/service/controls/TokenProvider.aidl b/core/java/android/service/controls/TokenProvider.aidl
deleted file mode 100644
index 8f4b795..0000000
--- a/core/java/android/service/controls/TokenProvider.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-package android.service.controls;
-
-/** @hide */
-interface TokenProvider {
-    void setAuthToken(String token);
-    String getAccountName();
-}
\ No newline at end of file
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 5bf1975..0b9a8af 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -172,7 +172,7 @@
         @Override
         public void prepareImage(InstallationFileParcel[] addedFiles, String[] removedFiles) {
             if (!nativePrepareImage(mId, addedFiles, removedFiles)) {
-                Slog.w(TAG, "Failed to destroy loader: " + mId);
+                Slog.w(TAG, "Failed to prepare image for data loader: " + mId);
             }
         }
     }
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 74b9136..1beeb65 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -237,16 +237,24 @@
     public StatusBarNotification cloneLight() {
         final Notification no = new Notification();
         this.notification.cloneInto(no, false); // light copy
-        return new StatusBarNotification(this.pkg, this.opPkg,
-                this.id, this.tag, this.uid, this.initialPid,
-                no, this.user, this.overrideGroupKey, this.postTime);
+        return cloneShallow(no);
     }
 
     @Override
     public StatusBarNotification clone() {
-        return new StatusBarNotification(this.pkg, this.opPkg,
+        return cloneShallow(this.notification.clone());
+    }
+
+    /**
+     * @param notification Some kind of clone of this.notification.
+     * @return A shallow copy of self, with notification in place of this.notification.
+     */
+    StatusBarNotification cloneShallow(Notification notification) {
+        StatusBarNotification result = new StatusBarNotification(this.pkg, this.opPkg,
                 this.id, this.tag, this.uid, this.initialPid,
-                this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
+                notification, this.user, this.overrideGroupKey, this.postTime);
+        result.setInstanceId(this.mInstanceId);
+        return result;
     }
 
     @Override
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index ee3a8a7..a8db50e 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -140,7 +140,7 @@
         @Override
         public String toString() {
             return "OffsetResult{"
-                    + "mTimeZone=" + mTimeZone
+                    + "mTimeZone(ID)=" + mTimeZone.getID()
                     + ", mIsOnlyMatch=" + mIsOnlyMatch
                     + '}';
         }
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index 5ccdd30..565f694 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -27,7 +27,7 @@
  */
 oneway interface ITaskOrganizer {
     void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
-    void taskVanished(in IWindowContainer container);
+    void taskVanished(in ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Called upon completion of
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 73601d9..84ac90b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -724,11 +724,12 @@
 
     /**
      * Called to get the expected window insets.
-     * TODO(window-context): Remove when new insets flag is available.
+     *
+     * @return {@code true} if system bars are always comsumed.
      */
-    void getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
+    boolean getWindowInsets(in WindowManager.LayoutParams attrs, int displayId,
             out Rect outContentInsets, out Rect outStableInsets,
-            out DisplayCutout.ParcelableWrapper displayCutout);
+            out DisplayCutout.ParcelableWrapper outDisplayCutout, out InsetsState outInsetsState);
 
     /**
      * Called to show global actions.
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 573d8fc..302d4f3 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -724,12 +724,13 @@
             mApplier = new SyncRtSurfaceTransactionApplier(mViewRoot.mView);
         }
         if (mViewRoot.mView.isHardwareAccelerated()) {
-            mApplier.scheduleApply(params);
+            mApplier.scheduleApply(false /* earlyWakeup */, params);
         } else {
             // Window doesn't support hardware acceleration, no synchronization for now.
             // TODO(b/149342281): use mViewRoot.mSurface.getNextFrameNumber() to sync on every
             //  frame instead.
-            mApplier.applyParams(new Transaction(), -1 /* frame */, params);
+            mApplier.applyParams(new Transaction(), -1 /* frame */, false /* earlyWakeup */,
+                    params);
         }
     }
 
@@ -992,4 +993,23 @@
         }
         return mViewRoot.mWindowAttributes.insetsFlags.behavior;
     }
+
+    /**
+     * At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
+     * setControl) we need to release the old leash. But we may have already scheduled
+     * a SyncRtSurfaceTransaction applier to use it from the RenderThread. To avoid
+     * synchronization issues we also release from the RenderThread so this release
+     * happens after any existing items on the work queue.
+     */
+    public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+        if (mViewRoot.mView != null && mViewRoot.mView.isHardwareAccelerated()) {
+            mViewRoot.registerRtFrameCallback(frame -> {
+                  sc.release();
+            });
+            // Make sure a frame gets scheduled.
+            mViewRoot.mView.invalidate();
+        } else {
+              sc.release();
+        }
+    }
 }
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index f07f1ce..252fc0c 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -117,7 +117,7 @@
             }
         }
         if (lastControl != null) {
-            lastControl.release();
+            lastControl.release(mController);
         }
     }
 
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 29ba56a..75f6eab 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -94,9 +94,9 @@
         dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
     }
 
-    public void release() {
+    public void release(InsetsController controller) {
         if (mLeash != null) {
-            mLeash.release();
+            controller.releaseSurfaceControlFromRt(mLeash);
         }
     }
 
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index e4aa410..c2ad74a 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -80,6 +80,12 @@
     })
     public @interface InternalInsetsType {}
 
+    /**
+     * Special value to be used to by methods returning an {@link InternalInsetsType} to indicate
+     * that the objects/parameters aren't associated with an {@link InternalInsetsType}
+     */
+    public static final int ITYPE_INVALID = -1;
+
     static final int FIRST_TYPE = 0;
 
     public static final int ITYPE_STATUS_BAR = FIRST_TYPE;
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index b04372a..3c22ed8 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -20,9 +20,11 @@
 import static android.view.RemoteAnimationTargetProto.CONTENT_INSETS;
 import static android.view.RemoteAnimationTargetProto.IS_TRANSLUCENT;
 import static android.view.RemoteAnimationTargetProto.LEASH;
+import static android.view.RemoteAnimationTargetProto.LOCAL_BOUNDS;
 import static android.view.RemoteAnimationTargetProto.MODE;
 import static android.view.RemoteAnimationTargetProto.POSITION;
 import static android.view.RemoteAnimationTargetProto.PREFIX_ORDER_INDEX;
+import static android.view.RemoteAnimationTargetProto.SCREEN_SPACE_BOUNDS;
 import static android.view.RemoteAnimationTargetProto.SOURCE_CONTAINER_BOUNDS;
 import static android.view.RemoteAnimationTargetProto.START_BOUNDS;
 import static android.view.RemoteAnimationTargetProto.START_LEASH;
@@ -130,19 +132,38 @@
      * The source position of the app, in screen spaces coordinates. If the position of the leash
      * is modified from the controlling app, any animation transform needs to be offset by this
      * amount.
+     * @deprecated Use {@link #localBounds} instead.
      */
+    @Deprecated
     @UnsupportedAppUsage
     public final Point position;
 
     /**
+     * Bounds of the target relative to its parent.
+     * When the app target animating on its parent, we need to use the local coordinates relative to
+     * its parent with {@code localBounds.left} & {@code localBounds.top} rather than using
+     * {@code position} in screen coordinates.
+     */
+    public final Rect localBounds;
+
+    /**
      * The bounds of the source container the app lives in, in screen space coordinates. If the crop
      * of the leash is modified from the controlling app, it needs to take the source container
      * bounds into account when calculating the crop.
+     * @deprecated Renamed to {@link #screenSpaceBounds}
      */
+    @Deprecated
     @UnsupportedAppUsage
     public final Rect sourceContainerBounds;
 
     /**
+     * Bounds of the target relative to the screen. If the crop of the leash is modified from the
+     * controlling app, it needs to take the screen space bounds into account when calculating the
+     * crop.
+     */
+    public final Rect screenSpaceBounds;
+
+    /**
      * The starting bounds of the source container in screen space coordinates. This is {@code null}
      * if the animation target isn't MODE_CHANGING. Since this is the starting bounds, it's size
      * should be equivalent to the size of the starting thumbnail. Note that sourceContainerBounds
@@ -165,7 +186,8 @@
 
     public RemoteAnimationTarget(int taskId, int mode, SurfaceControl leash, boolean isTranslucent,
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
-            Rect sourceContainerBounds, WindowConfiguration windowConfig, boolean isNotInRecents,
+            Rect localBounds, Rect screenSpaceBounds,
+            WindowConfiguration windowConfig, boolean isNotInRecents,
             SurfaceControl startLeash, Rect startBounds) {
         this.mode = mode;
         this.taskId = taskId;
@@ -175,7 +197,9 @@
         this.contentInsets = new Rect(contentInsets);
         this.prefixOrderIndex = prefixOrderIndex;
         this.position = new Point(position);
-        this.sourceContainerBounds = new Rect(sourceContainerBounds);
+        this.localBounds = new Rect(localBounds);
+        this.sourceContainerBounds = new Rect(screenSpaceBounds);
+        this.screenSpaceBounds = new Rect(screenSpaceBounds);
         this.windowConfiguration = windowConfig;
         this.isNotInRecents = isNotInRecents;
         this.startLeash = startLeash;
@@ -191,7 +215,9 @@
         contentInsets = in.readParcelable(null);
         prefixOrderIndex = in.readInt();
         position = in.readParcelable(null);
+        localBounds = in.readParcelable(null);
         sourceContainerBounds = in.readParcelable(null);
+        screenSpaceBounds = in.readParcelable(null);
         windowConfiguration = in.readParcelable(null);
         isNotInRecents = in.readBoolean();
         startLeash = in.readParcelable(null);
@@ -213,7 +239,9 @@
         dest.writeParcelable(contentInsets, 0 /* flags */);
         dest.writeInt(prefixOrderIndex);
         dest.writeParcelable(position, 0 /* flags */);
+        dest.writeParcelable(localBounds, 0 /* flags */);
         dest.writeParcelable(sourceContainerBounds, 0 /* flags */);
+        dest.writeParcelable(screenSpaceBounds, 0 /* flags */);
         dest.writeParcelable(windowConfiguration, 0 /* flags */);
         dest.writeBoolean(isNotInRecents);
         dest.writeParcelable(startLeash, 0 /* flags */);
@@ -229,6 +257,8 @@
         pw.print(" prefixOrderIndex="); pw.print(prefixOrderIndex);
         pw.print(" position="); position.printShortString(pw);
         pw.print(" sourceContainerBounds="); sourceContainerBounds.printShortString(pw);
+        pw.print(" screenSpaceBounds="); screenSpaceBounds.printShortString(pw);
+        pw.print(" localBounds="); localBounds.printShortString(pw);
         pw.println();
         pw.print(prefix); pw.print("windowConfiguration="); pw.println(windowConfiguration);
         pw.print(prefix); pw.print("leash="); pw.println(leash);
@@ -245,6 +275,8 @@
         proto.write(PREFIX_ORDER_INDEX, prefixOrderIndex);
         position.dumpDebug(proto, POSITION);
         sourceContainerBounds.dumpDebug(proto, SOURCE_CONTAINER_BOUNDS);
+        screenSpaceBounds.dumpDebug(proto, SCREEN_SPACE_BOUNDS);
+        localBounds.dumpDebug(proto, LOCAL_BOUNDS);
         windowConfiguration.dumpDebug(proto, WINDOW_CONFIGURATION);
         if (startLeash != null) {
             startLeash.dumpDebug(proto, START_LEASH);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index fb7c04a..1f7c3504 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -605,7 +605,7 @@
                 mTmpRect.set(0, 0, mSurfaceWidth, mSurfaceHeight);
             }
             SyncRtSurfaceTransactionApplier applier = new SyncRtSurfaceTransactionApplier(this);
-            applier.scheduleApply(
+            applier.scheduleApply(false /* earlyWakeup */,
                     new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(mSurfaceControl)
                             .withWindowCrop(mTmpRect)
                             .build());
diff --git a/core/java/android/view/SyncRtSurfaceTransactionApplier.java b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
index 206e4f9..9c97f3e 100644
--- a/core/java/android/view/SyncRtSurfaceTransactionApplier.java
+++ b/core/java/android/view/SyncRtSurfaceTransactionApplier.java
@@ -53,10 +53,11 @@
     /**
      * Schedules applying surface parameters on the next frame.
      *
+     * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
      *               this method to avoid synchronization issues.
      */
-    public void scheduleApply(final SurfaceParams... params) {
+    public void scheduleApply(boolean earlyWakeup, final SurfaceParams... params) {
         if (mTargetViewRootImpl == null) {
             return;
         }
@@ -66,7 +67,7 @@
                 return;
             }
             Transaction t = new Transaction();
-            applyParams(t, frame, params);
+            applyParams(t, frame, earlyWakeup, params);
         });
 
         // Make sure a frame gets scheduled.
@@ -77,10 +78,12 @@
      * Applies surface parameters on the next frame.
      * @param t transaction to apply all parameters in.
      * @param frame frame to synchronize to. Set -1 when sync is not required.
+     * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
      *               this method to avoid synchronization issues.
      */
-    void applyParams(Transaction t, long frame, final SurfaceParams... params) {
+     void applyParams(Transaction t, long frame, boolean earlyWakeup,
+            final SurfaceParams... params) {
         for (int i = params.length - 1; i >= 0; i--) {
             SurfaceParams surfaceParams = params[i];
             SurfaceControl surface = surfaceParams.surface;
@@ -89,7 +92,9 @@
             }
             applyParams(t, surfaceParams, mTmpFloat9);
         }
-        t.setEarlyWakeup();
+        if (earlyWakeup) {
+            t.setEarlyWakeup();
+        }
         t.apply();
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b6c46be..7d4ec3d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3714,7 +3714,7 @@
         if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
             final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
                     AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
-            extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+            extraRenderingInfo.setLayoutSize(getLayoutParams().width, getLayoutParams().height);
             info.setExtraRenderingInfo(extraRenderingInfo);
         }
     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8d3cffc..9228fbd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1735,7 +1735,7 @@
             mBoundsLayer = new SurfaceControl.Builder(mSurfaceSession)
                     .setContainerLayer()
                     .setName("Bounds for - " + getTitle().toString())
-                    .setParent(mSurfaceControl)
+                    .setParent(getRenderSurfaceControl())
                     .build();
             setBoundsLayerCrop();
             mTransaction.show(mBoundsLayer).apply();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6435b42..4050da1 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -18,8 +18,11 @@
 
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_VISIBLE;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 
 import android.annotation.NonNull;
 import android.app.ResourcesManager;
@@ -215,9 +218,9 @@
     @Override
     public WindowMetrics getCurrentWindowMetrics() {
         final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
-        final Rect bound = getCurrentBounds(context);
+        final Rect bounds = getCurrentBounds(context);
 
-        return new WindowMetrics(toSize(bound), computeWindowInsets());
+        return new WindowMetrics(toSize(bounds), computeWindowInsets(bounds));
     }
 
     private static Rect getCurrentBounds(Context context) {
@@ -228,7 +231,8 @@
 
     @Override
     public WindowMetrics getMaximumWindowMetrics() {
-        return new WindowMetrics(toSize(getMaximumBounds()), computeWindowInsets());
+        final Rect maxBounds = getMaximumBounds();
+        return new WindowMetrics(toSize(maxBounds), computeWindowInsets(maxBounds));
     }
 
     private Size toSize(Rect frame) {
@@ -244,9 +248,8 @@
         return new Rect(0, 0, displaySize.x, displaySize.y);
     }
 
-    private WindowInsets computeWindowInsets() {
-        // TODO(b/118118435): This can only be properly implemented
-        //  once we flip the new insets mode flag.
+    // TODO(b/150095967): Set window type to LayoutParams
+    private WindowInsets computeWindowInsets(Rect bounds) {
         // Initialize params which used for obtaining all system insets.
         final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
         params.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
@@ -257,21 +260,34 @@
         params.setFitInsetsTypes(0);
         params.setFitInsetsSides(0);
 
-        return getWindowInsetsFromServer(params);
+        return getWindowInsetsFromServer(params, bounds);
     }
 
-    private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs) {
+    private WindowInsets getWindowInsetsFromServer(WindowManager.LayoutParams attrs, Rect bounds) {
         try {
             final Rect systemWindowInsets = new Rect();
             final Rect stableInsets = new Rect();
             final DisplayCutout.ParcelableWrapper displayCutout =
                     new DisplayCutout.ParcelableWrapper();
-            WindowManagerGlobal.getWindowManagerService().getWindowInsets(attrs,
-                    mContext.getDisplayId(), systemWindowInsets, stableInsets, displayCutout);
-            return new WindowInsets.Builder()
-                    .setSystemWindowInsets(Insets.of(systemWindowInsets))
-                    .setStableInsets(Insets.of(stableInsets))
-                    .setDisplayCutout(displayCutout.get()).build();
+            final InsetsState insetsState = new InsetsState();
+            final boolean alwaysConsumeSystemBars = WindowManagerGlobal.getWindowManagerService()
+                    .getWindowInsets(attrs, mContext.getDisplayId(), systemWindowInsets,
+                    stableInsets, displayCutout, insetsState);
+            final boolean isScreenRound =
+                    mContext.getResources().getConfiguration().isScreenRound();
+            if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+                return insetsState.calculateInsets(bounds, null /* ignoringVisibilityState*/,
+                        isScreenRound, alwaysConsumeSystemBars, displayCutout.get(),
+                        systemWindowInsets, stableInsets, SOFT_INPUT_ADJUST_NOTHING,
+                        SYSTEM_UI_FLAG_VISIBLE, null /* typeSideMap */);
+            } else {
+                return new WindowInsets.Builder()
+                        .setAlwaysConsumeSystemBars(alwaysConsumeSystemBars)
+                        .setRound(isScreenRound)
+                        .setSystemWindowInsets(Insets.of(systemWindowInsets))
+                        .setStableInsets(Insets.of(stableInsets))
+                        .setDisplayCutout(displayCutout.get()).build();
+            }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index f2cbf89..5fccf40 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -559,14 +559,6 @@
     public static final String ACTION_ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT =
             "android.view.accessibility.action.ARGUMENT_PRESS_AND_HOLD_DURATION_MILLIS_INT";
 
-    /**
-     * Argument to represent the IME action Id to press the returning key on a node.
-     * For use with R.id.accessibilityActionImeEnter
-     * @hide
-     */
-    public static final String ACTION_ARGUMENT_IME_ACTION_ID_INT =
-            "android.view.accessibility.action.ARGUMENT_IME_ACTION_ID_INT";
-
     // Focus types
 
     /**
@@ -649,7 +641,7 @@
      * argument.
      * <p>
      * The data can be retrieved from the {@link ExtraRenderingInfo} returned by
-     * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutParams},
+     * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutSize},
      * {@link ExtraRenderingInfo#getTextSizeInPx()} and
      * {@link ExtraRenderingInfo#getTextSizeUnit()}. For layout params, it is supported by both
      * {@link TextView} and {@link ViewGroup}. For text size and unit, it is only supported by
@@ -657,7 +649,6 @@
      *
      * @see #refreshWithExtraData(String, Bundle)
      */
-
     public static final String EXTRA_DATA_RENDERING_INFO_KEY =
             "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY";
 
@@ -1038,8 +1029,8 @@
      *                     with this mechanism is generally expensive to retrieve, so should only be
      *                     requested when needed. See
      *                     {@link #EXTRA_DATA_RENDERING_INFO_KEY},
-     *                     {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and
-     *                     {@link #getAvailableExtraData()}.
+     *                     {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY},
+     *                     {@link #getAvailableExtraData()} and {@link #getExtraRenderingInfo()}.
      * @param args A bundle of arguments for the request. These depend on the particular request.
      *
      * @return {@code true} if the refresh succeeded. {@code false} if the {@link View} represented
@@ -2437,9 +2428,13 @@
     }
 
     /**
-     * Gets the conformance info if the node is meant to be refreshed with extra data.
+     * Gets the {@link ExtraRenderingInfo extra rendering info} if the node is meant to be
+     * refreshed with extra data to examine rendering related accessibility issues.
      *
-     * @return The conformance info.
+     * @return The {@link ExtraRenderingInfo extra rendering info}.
+     *
+     * @see #EXTRA_DATA_RENDERING_INFO_KEY
+     * @see #refreshWithExtraData(String, Bundle)
      */
     @Nullable
     public ExtraRenderingInfo getExtraRenderingInfo() {
@@ -2447,14 +2442,15 @@
     }
 
     /**
-     * Sets the conformance info if the node is meant to be refreshed with extra data.
+     * Sets the extra rendering info, <code>extraRenderingInfo<code/>, if the node is meant to be
+     * refreshed with extra data.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
      *   {@link android.accessibilityservice.AccessibilityService}.
      *   This class is made immutable before being delivered to an AccessibilityService.
      * </p>
      *
-     * @param extraRenderingInfo The conformance info.
+     * @param extraRenderingInfo The {@link ExtraRenderingInfo extra rendering info}.
      * @hide
      */
     public void setExtraRenderingInfo(@NonNull ExtraRenderingInfo extraRenderingInfo) {
@@ -3925,7 +3921,7 @@
         }
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
-            parcel.writeValue(mExtraRenderingInfo.getLayoutParams());
+            parcel.writeValue(mExtraRenderingInfo.getLayoutSize());
             parcel.writeFloat(mExtraRenderingInfo.getTextSizeInPx());
             parcel.writeInt(mExtraRenderingInfo.getTextSizeUnit());
         }
@@ -4189,7 +4185,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
             if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle();
             mExtraRenderingInfo = ExtraRenderingInfo.obtain();
-            mExtraRenderingInfo.mLayoutParams = (Size) parcel.readValue(null);
+            mExtraRenderingInfo.mLayoutSize = (Size) parcel.readValue(null);
             mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat();
             mExtraRenderingInfo.mTextSizeUnit = parcel.readInt();
         }
@@ -4969,10 +4965,11 @@
                 new AccessibilityAction(R.id.accessibilityActionPressAndHold);
 
         /**
-         * Action to send an ime action which is from
-         * {@link android.view.inputmethod.EditorInfo#actionId}. This action would be
+         * Action to send an ime actionId which is from
+         * {@link android.view.inputmethod.EditorInfo#actionId}. This ime actionId sets by
+         * {@link TextView#setImeActionLabel(CharSequence, int)}, or it would be
          * {@link android.view.inputmethod.EditorInfo#IME_ACTION_UNSPECIFIED} if no specific
-         * actionId defined. A node should expose this action only for views that are currently
+         * actionId has set. A node should expose this action only for views that are currently
          * with input focus and editable.
          */
         @NonNull public static final AccessibilityAction ACTION_IME_ENTER =
@@ -5808,7 +5805,7 @@
         private static final SynchronizedPool<ExtraRenderingInfo> sPool =
                 new SynchronizedPool<>(MAX_POOL_SIZE);
 
-        private Size mLayoutParams;
+        private Size mLayoutSize;
         private float mTextSizeInPx = UNDEFINED_VALUE;
         private int mTextSizeUnit = UNDEFINED_VALUE;
 
@@ -5828,32 +5825,36 @@
         /** Obtains a pooled instance that is a clone of another one. */
         private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) {
             ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain();
-            extraRenderingInfo.mLayoutParams = other.mLayoutParams;
+            extraRenderingInfo.mLayoutSize = other.mLayoutSize;
             extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx;
             extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit;
             return extraRenderingInfo;
         }
 
         /**
-         * Creates a new conformance info of a view, and this new instance is initialized from
+         * Creates a new rendering info of a view, and this new instance is initialized from
          * the given <code>other</code>.
          *
          * @param other The instance to clone.
          */
         private ExtraRenderingInfo(@Nullable ExtraRenderingInfo other) {
             if (other != null) {
-                mLayoutParams = other.mLayoutParams;
+                mLayoutSize = other.mLayoutSize;
                 mTextSizeInPx = other.mTextSizeInPx;
                 mTextSizeUnit = other.mTextSizeUnit;
             }
         }
 
         /**
+         * Gets the size object containing the height and the width of layout params if the node is
+         * a {@link ViewGroup} or a {@link TextView}, or null otherwise. Useful for accessibility
+         * scanning tool to understand whether the text is scalable and fits the view or not.
+         *
          * @return a {@link Size} stores layout height and layout width of the view,
          *         or null otherwise.
          */
-        public @Nullable Size getLayoutParams() {
-            return mLayoutParams;
+        public @Nullable Size getLayoutSize() {
+            return mLayoutSize;
         }
 
         /**
@@ -5863,11 +5864,15 @@
          * @param height The layout height.
          * @hide
          */
-        public void setLayoutParams(int width, int height) {
-            mLayoutParams = new Size(width, height);
+        public void setLayoutSize(int width, int height) {
+            mLayoutSize = new Size(width, height);
         }
 
         /**
+         * Gets the text size if the node is a {@link TextView}, or -1 otherwise.  Useful for
+         * accessibility scanning tool to understand whether the text is scalable and fits the view
+         * or not.
+         *
          * @return the text size of a {@code TextView}, or -1 otherwise.
          */
         public float getTextSizeInPx() {
@@ -5885,6 +5890,11 @@
         }
 
         /**
+         * Gets the text size unit if the node is a {@link TextView}, or -1 otherwise.
+         * Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and
+         * convert from other units. Useful for accessibility scanning tool to understand whether
+         * the text is scalable and fits the view or not.
+         *
          * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a
          *         {@code TextView}, or -1 otherwise.
          *
@@ -5915,7 +5925,7 @@
         }
 
         private void clear() {
-            mLayoutParams = null;
+            mLayoutSize = null;
             mTextSizeInPx = UNDEFINED_VALUE;
             mTextSizeUnit = UNDEFINED_VALUE;
         }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index b7b54c8..b988927 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -217,6 +217,15 @@
     public static final int DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 3;
 
     /** @hide */
+    @IntDef(flag = false, value = {
+            DATA_SHARE_ERROR_UNKNOWN,
+            DATA_SHARE_ERROR_CONCURRENT_REQUEST,
+            DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DataShareError {}
+
+    /** @hide */
     public static final int RESULT_CODE_OK = 0;
     /** @hide */
     public static final int RESULT_CODE_TRUE = 1;
diff --git a/core/java/android/view/contentcapture/DataShareWriteAdapter.java b/core/java/android/view/contentcapture/DataShareWriteAdapter.java
index 2beaede..3b5b756 100644
--- a/core/java/android/view/contentcapture/DataShareWriteAdapter.java
+++ b/core/java/android/view/contentcapture/DataShareWriteAdapter.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.os.ParcelFileDescriptor;
+import android.view.contentcapture.ContentCaptureManager.DataShareError;
 
 /** Adapter class used by apps to share data with the Content Capture service. */
 public interface DataShareWriteAdapter {
@@ -42,7 +43,7 @@
      *
      * @param errorCode the error code corresponding to an ERROR_* value.
      */
-    default void onError(int errorCode) {
+    default void onError(@DataShareError int errorCode) {
         /* do nothing - stub */
     }
 }
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index ff80ef7..f62a28e 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -268,17 +268,28 @@
     protected abstract boolean allowFileSchemeCookiesImpl();
 
     /**
-     * Sets whether the application's {@link WebView} instances should send and
-     * accept cookies for file scheme URLs.
-     * Use of cookies with file scheme URLs is potentially insecure and turned
-     * off by default.
-     * Do not use this feature unless you can be sure that no unintentional
-     * sharing of cookie data can take place.
+     * Sets whether the application's {@link WebView} instances should send and accept cookies for
+     * file scheme URLs.
      * <p>
-     * Note that calls to this method will have no effect if made after a
-     * {@link WebView} or CookieManager instance has been created.
+     * Use of cookies with file scheme URLs is potentially insecure and turned off by default. All
+     * {@code file://} URLs share all their cookies, which may lead to leaking private app cookies
+     * (ex. any malicious file can access cookies previously set by other (trusted) files).
+     * <p class="note">
+     * Loading content via {@code file://} URLs is generally discouraged. See the note in
+     * {@link WebSettings#setAllowFileAccess}.
+     * Using <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+     * androidx.webkit.WebViewAssetLoader</a> to load files over {@code http(s)://} URLs allows
+     * the standard web security model to be used for setting and sharing cookies for local files.
+     * <p>
+     * Note that calls to this method will have no effect if made after calling other
+     * {@link CookieManager} APIs.
+     *
+     * @deprecated This setting is not secure, please use
+     *             <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+     *             androidx.webkit.WebViewAssetLoader</a> instead.
      */
     // Static for backward compatibility.
+    @Deprecated
     public static void setAcceptFileSchemeCookies(boolean accept) {
         getInstance().setAcceptFileSchemeCookiesImpl(accept);
     }
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 53541f7..35dd576 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -983,48 +983,63 @@
     public abstract void setJavaScriptEnabled(boolean flag);
 
     /**
-     * Sets whether JavaScript running in the context of a file scheme URL
-     * should be allowed to access content from any origin. This includes
-     * access to content from other file scheme URLs. See
-     * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive,
-     * and therefore secure policy, this setting should be disabled.
-     * Note that this setting affects only JavaScript access to file scheme
-     * resources. Other access to such resources, for example, from image HTML
-     * elements, is unaffected. To prevent possible violation of same domain policy
-     * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
-     * you should explicitly set this value to {@code false}.
+     * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+     * access content from <i>any</i> origin. This includes access to content from other file
+     * scheme URLs or web contexts. Note that some access such as image HTML elements doesn't
+     * follow same-origin rules and isn't affected by this setting.
+     * <p>
+     * <b>Don't</b> enable this setting if you open files that may be created or altered by
+     * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+     * context to launch cross-site scripting attacks, either accessing arbitrary local files
+     * including WebView cookies, app private data or even credentials used on arbitrary web sites.
+     * <p class="note">
+     * Loading content via {@code file://} URLs is generally discouraged. See the note in
+     * {@link #setAllowFileAccess}.
      * <p>
      * The default value is {@code true} for apps targeting
-     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
-     * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
-     * and above.
+     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, and {@code false}
+     * when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} and above. To prevent
+     * possible violation of same domain policy when targeting
+     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+     * explicitly set this value to {@code false}.
      *
-     * @param flag whether JavaScript running in the context of a file scheme
-     *             URL should be allowed to access content from any origin
+     * @param flag whether JavaScript running in the context of a file scheme URL should be allowed
+     *             to access content from any origin
+     * @deprecated This setting is not secure, please use
+     *             <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+     *             androidx.webkit.WebViewAssetLoader</a> to load file content securely.
      */
+    @Deprecated
     public abstract void setAllowUniversalAccessFromFileURLs(boolean flag);
 
     /**
-     * Sets whether JavaScript running in the context of a file scheme URL
-     * should be allowed to access content from other file scheme URLs. To
-     * enable the most restrictive, and therefore secure, policy this setting
-     * should be disabled. Note that the value of this setting is ignored if
-     * the value of {@link #getAllowUniversalAccessFromFileURLs} is {@code true}.
-     * Note too, that this setting affects only JavaScript access to file scheme
-     * resources. Other access to such resources, for example, from image HTML
-     * elements, is unaffected. To prevent possible violation of same domain policy
-     * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
-     * you should explicitly set this value to {@code false}.
+     * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+     * access content from other file scheme URLs. Note that some accesses such as image HTML
+     * elements don't follow same-origin rules and aren't affected by this setting.
      * <p>
-     * The default value is {@code true} for apps targeting
-     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
-     * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
-     * and above.
+     * <b>Don't</b> enable this setting if you open files that may be created or altered by
+     * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+     * context to access arbitrary local files including WebView cookies and app private data.
+     * <p class="note">
+     * Loading content via {@code file://} URLs is generally discouraged. See the note in
+     * {@link #setAllowFileAccess}.
+     * <p>
+     * Note that the value of this setting is ignored if the value of
+     * {@link #getAllowUniversalAccessFromFileURLs} is {@code true}. The default value is
+     * {@code true} for apps targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1}
+     * and below, and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
+     * and above. To prevent possible violation of same domain policy when targeting
+     * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+     * explicitly set this value to {@code false}.
      *
      * @param flag whether JavaScript running in the context of a file scheme
      *             URL should be allowed to access content from other file
      *             scheme URLs
+     * @deprecated This setting is not secure, please use
+     *             <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+     *             androidx.webkit.WebViewAssetLoader</a> to load file content securely.
      */
+    @Deprecated
     public abstract void setAllowFileAccessFromFileURLs(boolean flag);
 
     /**
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 13c1f67..816612f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4587,7 +4587,8 @@
         protected int mHorizontalGravity;
         // Offsets the hotspot point up, so that cursor is not hidden by the finger when moving up
         private float mTouchOffsetY;
-        // Where the touch position should be on the handle to ensure a maximum cursor visibility
+        // Where the touch position should be on the handle to ensure a maximum cursor visibility.
+        // This is the distance in pixels from the top of the handle view.
         private float mIdealVerticalOffset;
         // Parent's (TextView) previous position in window
         private int mLastParentX, mLastParentY;
@@ -4612,6 +4613,11 @@
         // when magnifier is used.
         private float mTextViewScaleX;
         private float mTextViewScaleY;
+        /**
+         * The vertical distance in pixels from finger to the cursor Y while dragging.
+         * See {@link Editor.InsertionPointCursorController#getLineDuringDrag}.
+         */
+        private final int mIdealFingerToCursorOffset;
 
         private HandleView(Drawable drawableLtr, Drawable drawableRtl, final int id) {
             super(mTextView.getContext());
@@ -4633,12 +4639,17 @@
             final int handleHeight = getPreferredHeight();
             mTouchOffsetY = -0.3f * handleHeight;
             mIdealVerticalOffset = 0.7f * handleHeight;
+            mIdealFingerToCursorOffset = (int)(mIdealVerticalOffset - mTouchOffsetY);
         }
 
         public float getIdealVerticalOffset() {
             return mIdealVerticalOffset;
         }
 
+        final int getIdealFingerToCursorOffset() {
+            return mIdealFingerToCursorOffset;
+        }
+
         void setDrawables(final Drawable drawableLtr, final Drawable drawableRtl) {
             mDrawableLtr = drawableLtr;
             mDrawableRtl = drawableRtl;
@@ -6123,36 +6134,34 @@
          */
         private int getLineDuringDrag(MotionEvent event) {
             final Layout layout = mTextView.getLayout();
-            if (mTouchState.isOnHandle()) {
-                // The drag was initiated from the handle, so no need to apply the snap logic. See
-                // InsertionHandleView.touchThrough().
+            if (mPrevLineDuringDrag == UNSET_LINE) {
                 return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
             }
+            // In case of touch through on handle (when isOnHandle() returns true), event.getY()
+            // returns the midpoint of the cursor vertical bar, while event.getRawY() returns the
+            // finger location on the screen. See {@link InsertionHandleView#touchThrough}.
+            final float fingerY = mTouchState.isOnHandle()
+                    ? event.getRawY() - mTextView.getLocationOnScreen()[1]
+                    : event.getY();
+            final float cursorY = fingerY - getHandle().getIdealFingerToCursorOffset();
+            int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
             if (mIsTouchSnappedToHandleDuringDrag) {
-                float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
-                return getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
-            }
-            int line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, event.getY());
-            if (mPrevLineDuringDrag == UNSET_LINE || line <= mPrevLineDuringDrag) {
-                // User's finger is on the same line or moving up; continue positioning the cursor
-                // directly at the touch location.
+                // Just returns the line hit by cursor Y when already snapped.
                 return line;
             }
-            // User's finger is moving downwards; delay jumping to the lower line to allow the
-            // touch to move to the handle.
-            float cursorY = event.getY() - getHandle().getIdealVerticalOffset();
-            line = getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, cursorY);
             if (line < mPrevLineDuringDrag) {
-                return mPrevLineDuringDrag;
+                // The cursor Y aims too high & not yet snapped, check the finger Y.
+                // If finger Y is moving downwards, don't jump to lower line (until snap).
+                // If finger Y is moving upwards, can jump to upper line.
+                return Math.min(mPrevLineDuringDrag,
+                        getCurrentLineAdjustedForSlop(layout, mPrevLineDuringDrag, fingerY));
             }
-            // User's finger is now over the handle, at the ideal offset from the cursor. From now
-            // on, position the cursor higher up from the actual touch location so that the user's
-            // finger stays "snapped" to the handle. This provides better visibility of the text.
+            // The cursor Y aims not too high, so snap!
             mIsTouchSnappedToHandleDuringDrag = true;
             if (TextView.DEBUG_CURSOR) {
                 logCursor("InsertionPointCursorController",
-                        "snapped touch to handle: eventY=%d, cursorY=%d, mLastLine=%d, line=%d",
-                        (int) event.getY(), (int) cursorY, mPrevLineDuringDrag, line);
+                        "snapped touch to handle: fingerY=%d, cursorY=%d, mLastLine=%d, line=%d",
+                        (int) fingerY, (int) cursorY, mPrevLineDuringDrag, line);
             }
             return line;
         }
@@ -6252,7 +6261,7 @@
             }
         }
 
-        private InsertionHandleView getHandle() {
+        public InsertionHandleView getHandle() {
             if (mHandle == null) {
                 loadHandleDrawables(false /* overwrite */);
                 mHandle = new InsertionHandleView(mSelectHandleCenter);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f3243aa..0d82065 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11763,13 +11763,8 @@
             if (isTextEditable() && isFocused()) {
                 CharSequence imeActionLabel = mContext.getResources().getString(
                         com.android.internal.R.string.keyboardview_keycode_enter);
-                if (getImeActionId() != 0 && getImeActionLabel() != null) {
+                if (getImeActionLabel() != null) {
                     imeActionLabel = getImeActionLabel();
-                    final int imeActionId = getImeActionId();
-                    // put ime action id into the extra data with ACTION_ARGUMENT_IME_ACTION_ID_INT.
-                    final Bundle argument = info.getExtras();
-                    argument.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_IME_ACTION_ID_INT,
-                            imeActionId);
                 }
                 AccessibilityNodeInfo.AccessibilityAction action =
                         new AccessibilityNodeInfo.AccessibilityAction(
@@ -11881,7 +11876,7 @@
         if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) {
             final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo =
                     AccessibilityNodeInfo.ExtraRenderingInfo.obtain();
-            extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height);
+            extraRenderingInfo.setLayoutSize(getLayoutParams().width, getLayoutParams().height);
             extraRenderingInfo.setTextSizeInPx(getTextSize());
             extraRenderingInfo.setTextSizeUnit(getTextSizeUnit());
             info.setExtraRenderingInfo(extraRenderingInfo);
@@ -12100,13 +12095,7 @@
             } return true;
             case R.id.accessibilityActionImeEnter: {
                 if (isFocused() && isTextEditable()) {
-                    final int imeActionId = (arguments != null) ? arguments.getInt(
-                            AccessibilityNodeInfo.ACTION_ARGUMENT_IME_ACTION_ID_INT,
-                            EditorInfo.IME_ACTION_UNSPECIFIED)
-                            : EditorInfo.IME_ACTION_UNSPECIFIED;
-                    if (imeActionId == getImeActionId()) {
-                        onEditorAction(imeActionId);
-                    }
+                    onEditorAction(getImeActionId());
                 }
             } return true;
             default: {
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 5cdcab0..54ea57a 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -56,6 +56,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -133,7 +134,7 @@
         // Keep track of state of shortcut settings
         final ContentObserver co = new ContentObserver(handler) {
             @Override
-            public void onChange(boolean selfChange, Uri uri, int userId) {
+            public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
                 if (userId == mUserId) {
                     onSettingsChanged();
                 }
diff --git a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
index 1daa505..79b34c0 100644
--- a/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
+++ b/core/java/com/android/internal/accessibility/common/ShortcutConstants.java
@@ -28,8 +28,6 @@
     private ShortcutConstants() {}
 
     public static final char SERVICES_SEPARATOR = ':';
-    public static final float DISABLED_ALPHA = 0.5f;
-    public static final float ENABLED_ALPHA = 1.0f;
 
     /**
      * Annotation for different user shortcut type UI type.
@@ -80,6 +78,21 @@
     }
 
     /**
+     * Annotation for different shortcut target.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            TargetType.ACCESSIBILITY_SERVICE,
+            TargetType.ACCESSIBILITY_ACTIVITY,
+            TargetType.WHITE_LISTING,
+    })
+    public @interface TargetType {
+        int ACCESSIBILITY_SERVICE = 0;
+        int ACCESSIBILITY_ACTIVITY = 1;
+        int WHITE_LISTING = 2;
+    }
+
+    /**
      * Annotation for different shortcut menu mode.
      *
      * {@code LAUNCH} for clicking list item to trigger the service callback.
diff --git a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
index 7df712f..717e780 100644
--- a/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
+++ b/core/java/com/android/internal/accessibility/util/ShortcutUtils.java
@@ -39,6 +39,33 @@
             new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
 
     /**
+     * Opts in component name into colon-separated {@link UserShortcutType}
+     * key's string in Settings.
+     *
+     * @param context The current context.
+     * @param shortcutType The preferred shortcut type user selected.
+     * @param componentId The component id that need to be opted out from Settings.
+     */
+    public static void optInValueToSettings(Context context, @UserShortcutType int shortcutType,
+            String componentId) {
+        final StringJoiner joiner = new StringJoiner(String.valueOf(SERVICES_SEPARATOR));
+        final String targetKey = convertToKey(shortcutType);
+        final String targetString = Settings.Secure.getString(context.getContentResolver(),
+                targetKey);
+
+        if (hasValueInSettings(context, shortcutType, componentId)) {
+            return;
+        }
+
+        if (!TextUtils.isEmpty(targetString)) {
+            joiner.add(targetString);
+        }
+        joiner.add(componentId);
+
+        Settings.Secure.putString(context.getContentResolver(), targetKey, joiner.toString());
+    }
+
+    /**
      * Opts out component name into colon-separated {@code shortcutType} key's string in Settings.
      *
      * @param context The current context.
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index 852deb2..c408641 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -23,10 +23,10 @@
 import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME;
 import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
 import static com.android.internal.accessibility.common.ShortcutConstants.AccessibilityServiceFragmentType;
-import static com.android.internal.accessibility.common.ShortcutConstants.DISABLED_ALPHA;
-import static com.android.internal.accessibility.common.ShortcutConstants.ENABLED_ALPHA;
 import static com.android.internal.accessibility.common.ShortcutConstants.ShortcutMenuMode;
+import static com.android.internal.accessibility.common.ShortcutConstants.TargetType;
 import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType;
+import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE;
 import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.COMPONENT_ID;
 import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.FRAGMENT_TYPE;
 import static com.android.internal.accessibility.common.ShortcutConstants.WhiteListingFeatureElementIndex.ICON_ID;
@@ -36,6 +36,7 @@
 import static com.android.internal.accessibility.util.AccessibilityUtils.setAccessibilityServiceState;
 import static com.android.internal.accessibility.util.ShortcutUtils.convertToUserType;
 import static com.android.internal.accessibility.util.ShortcutUtils.hasValuesInSettings;
+import static com.android.internal.accessibility.util.ShortcutUtils.optInValueToSettings;
 import static com.android.internal.accessibility.util.ShortcutUtils.optOutValueFromSettings;
 import static com.android.internal.util.Preconditions.checkArgument;
 
@@ -50,11 +51,12 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.res.TypedArray;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.storage.StorageManager;
 import android.provider.Settings;
+import android.text.BidiFormatter;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -62,28 +64,33 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
+import android.widget.Button;
+import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.Switch;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.internal.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Activity used to display and persist a service or feature target for the Accessibility button.
  */
 public class AccessibilityButtonChooserActivity extends Activity {
     @ShortcutType
-    private int mShortcutType;
+    private static int sShortcutType;
     @UserShortcutType
     private int mShortcutUserType;
     private final List<AccessibilityButtonTarget> mTargets = new ArrayList<>();
     private AlertDialog mAlertDialog;
+    private AlertDialog mEnableDialog;
     private TargetAdapter mTargetAdapter;
+    private AccessibilityButtonTarget mCurrentCheckedTarget;
 
     private static final String[][] WHITE_LISTING_FEATURES = {
             {
@@ -118,19 +125,19 @@
             requestWindowFeature(Window.FEATURE_NO_TITLE);
         }
 
-        mShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
+        sShortcutType = getIntent().getIntExtra(AccessibilityManager.EXTRA_SHORTCUT_TYPE,
                 /* unexpectedShortcutType */ -1);
-        final boolean existInShortcutType = (mShortcutType == ACCESSIBILITY_BUTTON)
-                || (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY);
-        checkArgument(existInShortcutType, "Unexpected shortcut type: " + mShortcutType);
+        final boolean existInShortcutType = (sShortcutType == ACCESSIBILITY_BUTTON)
+                || (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY);
+        checkArgument(existInShortcutType, "Unexpected shortcut type: " + sShortcutType);
 
-        mShortcutUserType = convertToUserType(mShortcutType);
+        mShortcutUserType = convertToUserType(sShortcutType);
 
-        mTargets.addAll(getServiceTargets(this, mShortcutType));
+        mTargets.addAll(getServiceTargets(this, sShortcutType));
 
         final String selectDialogTitle =
                 getString(R.string.accessibility_select_shortcut_menu_title);
-        mTargetAdapter = new TargetAdapter(mTargets, mShortcutType);
+        mTargetAdapter = new TargetAdapter(mTargets);
         mAlertDialog = new AlertDialog.Builder(this)
                 .setTitle(selectDialogTitle)
                 .setAdapter(mTargetAdapter, /* listener= */ null)
@@ -151,15 +158,21 @@
 
     private static List<AccessibilityButtonTarget> getServiceTargets(@NonNull Context context,
             @ShortcutType int shortcutType) {
+        final List<AccessibilityButtonTarget> targets = getInstalledServiceTargets(context);
+        final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+        final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
+        targets.removeIf(target -> !requiredTargets.contains(target.getId()));
+
+        return targets;
+    }
+
+    private static List<AccessibilityButtonTarget> getInstalledServiceTargets(
+            @NonNull Context context) {
         final List<AccessibilityButtonTarget> targets = new ArrayList<>();
         targets.addAll(getAccessibilityServiceTargets(context));
         targets.addAll(getAccessibilityActivityTargets(context));
         targets.addAll(getWhiteListingServiceTargets(context));
 
-        final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
-        final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(shortcutType);
-        targets.removeIf(target -> !requiredTargets.contains(target.getId()));
-
         return targets;
     }
 
@@ -174,6 +187,14 @@
 
         final List<AccessibilityButtonTarget> targets = new ArrayList<>(installedServices.size());
         for (AccessibilityServiceInfo info : installedServices) {
+            final int targetSdk =
+                    info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion;
+            final boolean hasRequestAccessibilityButtonFlag =
+                    (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+            if ((targetSdk < Build.VERSION_CODES.R) && !hasRequestAccessibilityButtonFlag
+                    && (sShortcutType == ACCESSIBILITY_BUTTON)) {
+                continue;
+            }
             targets.add(new AccessibilityButtonTarget(context, info));
         }
 
@@ -249,35 +270,31 @@
         }
     }
 
-    private void disableService(String componentId) {
+    private void setServiceEnabled(String componentId, boolean enabled) {
         if (isWhiteListingService(componentId)) {
-            setWhiteListingServiceEnabled(componentId, /* settingsValueOff */ 0);
+            setWhiteListingServiceEnabled(componentId,
+                    enabled ? /* settingsValueOn */ 1 : /* settingsValueOff */ 0);
         } else {
             final ComponentName componentName = ComponentName.unflattenFromString(componentId);
-            setAccessibilityServiceState(this, componentName, /* enabled= */ false);
+            setAccessibilityServiceState(this, componentName, enabled);
         }
     }
 
     private static class ViewHolder {
         View mItemView;
+        CheckBox mCheckBox;
         ImageView mIconView;
         TextView mLabelView;
-        FrameLayout mItemContainer;
-        ImageView mActionViewItem;
         Switch mSwitchItem;
     }
 
     private static class TargetAdapter extends BaseAdapter {
         @ShortcutMenuMode
         private int mShortcutMenuMode = ShortcutMenuMode.LAUNCH;
-        @ShortcutType
-        private int mShortcutButtonType;
         private List<AccessibilityButtonTarget> mButtonTargets;
 
-        TargetAdapter(List<AccessibilityButtonTarget> targets,
-                @ShortcutType int shortcutButtonType) {
+        TargetAdapter(List<AccessibilityButtonTarget> targets) {
             this.mButtonTargets = targets;
-            this.mShortcutButtonType = shortcutButtonType;
         }
 
         void setShortcutMenuMode(@ShortcutMenuMode int shortcutMenuMode) {
@@ -314,13 +331,11 @@
                         false);
                 holder = new ViewHolder();
                 holder.mItemView = convertView;
+                holder.mCheckBox = convertView.findViewById(
+                        R.id.accessibility_button_target_checkbox);
                 holder.mIconView = convertView.findViewById(R.id.accessibility_button_target_icon);
                 holder.mLabelView = convertView.findViewById(
                         R.id.accessibility_button_target_label);
-                holder.mItemContainer = convertView.findViewById(
-                        R.id.accessibility_button_target_item_container);
-                holder.mActionViewItem = convertView.findViewById(
-                        R.id.accessibility_button_target_view_item);
                 holder.mSwitchItem = convertView.findViewById(
                         R.id.accessibility_button_target_switch_item);
                 convertView.setTag(holder);
@@ -329,9 +344,6 @@
             }
 
             final AccessibilityButtonTarget target = mButtonTargets.get(position);
-            holder.mIconView.setImageDrawable(target.getDrawable());
-            holder.mLabelView.setText(target.getLabel());
-
             updateActionItem(context, holder, target);
 
             return convertView;
@@ -342,58 +354,42 @@
 
             switch (target.getFragmentType()) {
                 case AccessibilityServiceFragmentType.LEGACY:
-                    updateLegacyActionItemVisibility(context, holder);
+                    updateLegacyActionItemVisibility(holder, target);
                     break;
                 case AccessibilityServiceFragmentType.INVISIBLE:
-                    updateInvisibleActionItemVisibility(context, holder);
+                    updateInvisibleActionItemVisibility(holder, target);
                     break;
                 case AccessibilityServiceFragmentType.INTUITIVE:
                     updateIntuitiveActionItemVisibility(context, holder, target);
                     break;
                 case AccessibilityServiceFragmentType.BOUNCE:
-                    updateBounceActionItemVisibility(context, holder);
+                    updateBounceActionItemVisibility(holder, target);
                     break;
                 default:
                     throw new IllegalStateException("Unexpected fragment type");
             }
         }
 
-        private void updateLegacyActionItemVisibility(@NonNull Context context,
-                @NonNull ViewHolder holder) {
+        private void updateLegacyActionItemVisibility(@NonNull ViewHolder holder,
+                AccessibilityButtonTarget target) {
             final boolean isLaunchMenuMode = (mShortcutMenuMode == ShortcutMenuMode.LAUNCH);
-            final boolean isHardwareButtonTriggered =
-                    (mShortcutButtonType == ACCESSIBILITY_SHORTCUT_KEY);
-            final boolean enabledState = (isLaunchMenuMode || isHardwareButtonTriggered);
-            final ColorMatrix grayScaleMatrix = new ColorMatrix();
-            grayScaleMatrix.setSaturation(/* grayScale */0);
 
-            holder.mIconView.setColorFilter(enabledState
-                    ? null : new ColorMatrixColorFilter(grayScaleMatrix));
-            holder.mIconView.setAlpha(enabledState
-                    ? ENABLED_ALPHA : DISABLED_ALPHA);
-            holder.mLabelView.setEnabled(enabledState);
-            holder.mActionViewItem.setEnabled(enabledState);
-            holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
-            holder.mActionViewItem.setVisibility(View.VISIBLE);
+            holder.mCheckBox.setChecked(!isLaunchMenuMode && target.isChecked());
+            holder.mCheckBox.setVisibility(isLaunchMenuMode ? View.GONE : View.VISIBLE);
+            holder.mIconView.setImageDrawable(target.getDrawable());
+            holder.mLabelView.setText(target.getLabel());
             holder.mSwitchItem.setVisibility(View.GONE);
-            holder.mItemContainer.setVisibility(isLaunchMenuMode ? View.GONE : View.VISIBLE);
-            holder.mItemView.setEnabled(enabledState);
-            holder.mItemView.setClickable(!enabledState);
         }
 
-        private void updateInvisibleActionItemVisibility(@NonNull Context context,
-                @NonNull ViewHolder holder) {
-            holder.mIconView.setColorFilter(null);
-            holder.mIconView.setAlpha(ENABLED_ALPHA);
-            holder.mLabelView.setEnabled(true);
-            holder.mActionViewItem.setEnabled(true);
-            holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
-            holder.mActionViewItem.setVisibility(View.VISIBLE);
+        private void updateInvisibleActionItemVisibility(@NonNull ViewHolder holder,
+                AccessibilityButtonTarget target) {
+            final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
+
+            holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+            holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mIconView.setImageDrawable(target.getDrawable());
+            holder.mLabelView.setText(target.getLabel());
             holder.mSwitchItem.setVisibility(View.GONE);
-            holder.mItemContainer.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
-                    ? View.VISIBLE : View.GONE);
-            holder.mItemView.setEnabled(true);
-            holder.mItemView.setClickable(false);
         }
 
         private void updateIntuitiveActionItemVisibility(@NonNull Context context,
@@ -403,37 +399,31 @@
                     ? isWhiteListingServiceEnabled(context, target)
                     : isAccessibilityServiceEnabled(context, target);
 
-            holder.mIconView.setColorFilter(null);
-            holder.mIconView.setAlpha(ENABLED_ALPHA);
-            holder.mLabelView.setEnabled(true);
-            holder.mActionViewItem.setEnabled(true);
-            holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
-            holder.mActionViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+            holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mIconView.setImageDrawable(target.getDrawable());
+            holder.mLabelView.setText(target.getLabel());
             holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
             holder.mSwitchItem.setChecked(!isEditMenuMode && isServiceEnabled);
-            holder.mItemContainer.setVisibility(View.VISIBLE);
-            holder.mItemView.setEnabled(true);
-            holder.mItemView.setClickable(false);
         }
 
-        private void updateBounceActionItemVisibility(@NonNull Context context,
-                @NonNull ViewHolder holder) {
-            holder.mIconView.setColorFilter(null);
-            holder.mIconView.setAlpha(ENABLED_ALPHA);
-            holder.mLabelView.setEnabled(true);
-            holder.mActionViewItem.setEnabled(true);
-            holder.mActionViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
-            holder.mActionViewItem.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
-                    ? View.VISIBLE : View.GONE);
+        private void updateBounceActionItemVisibility(@NonNull ViewHolder holder,
+                AccessibilityButtonTarget target) {
+            final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
+
+            holder.mCheckBox.setChecked(isEditMenuMode && target.isChecked());
+            holder.mCheckBox.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+            holder.mIconView.setImageDrawable(target.getDrawable());
+            holder.mLabelView.setText(target.getLabel());
             holder.mSwitchItem.setVisibility(View.GONE);
-            holder.mItemContainer.setVisibility(View.VISIBLE);
-            holder.mItemView.setEnabled(true);
-            holder.mItemView.setClickable(false);
         }
     }
 
     private static class AccessibilityButtonTarget {
         private String mId;
+        @TargetType
+        private int mType;
+        private boolean mChecked;
         private CharSequence mLabel;
         private Drawable mDrawable;
         @AccessibilityServiceFragmentType
@@ -442,6 +432,8 @@
         AccessibilityButtonTarget(@NonNull Context context,
                 @NonNull AccessibilityServiceInfo serviceInfo) {
             this.mId = serviceInfo.getComponentName().flattenToString();
+            this.mType = TargetType.ACCESSIBILITY_SERVICE;
+            this.mChecked = isTargetShortcutUsed(context, mId);
             this.mLabel = serviceInfo.getResolveInfo().loadLabel(context.getPackageManager());
             this.mDrawable = serviceInfo.getResolveInfo().loadIcon(context.getPackageManager());
             this.mFragmentType = getAccessibilityServiceFragmentType(serviceInfo);
@@ -450,6 +442,8 @@
         AccessibilityButtonTarget(@NonNull Context context,
                 @NonNull AccessibilityShortcutInfo shortcutInfo) {
             this.mId = shortcutInfo.getComponentName().flattenToString();
+            this.mType = TargetType.ACCESSIBILITY_ACTIVITY;
+            this.mChecked = isTargetShortcutUsed(context, mId);
             this.mLabel = shortcutInfo.getActivityInfo().loadLabel(context.getPackageManager());
             this.mDrawable = shortcutInfo.getActivityInfo().loadIcon(context.getPackageManager());
             this.mFragmentType = AccessibilityServiceFragmentType.BOUNCE;
@@ -458,15 +452,29 @@
         AccessibilityButtonTarget(Context context, @NonNull String id, int labelResId,
                 int iconRes, @AccessibilityServiceFragmentType int fragmentType) {
             this.mId = id;
+            this.mType = TargetType.WHITE_LISTING;
+            this.mChecked = isTargetShortcutUsed(context, mId);
             this.mLabel = context.getText(labelResId);
             this.mDrawable = context.getDrawable(iconRes);
             this.mFragmentType = fragmentType;
         }
 
+        public void setChecked(boolean checked) {
+            mChecked = checked;
+        }
+
         public String getId() {
             return mId;
         }
 
+        public int getType() {
+            return mType;
+        }
+
+        public boolean isChecked() {
+            return mChecked;
+        }
+
         public CharSequence getLabel() {
             return mLabel;
         }
@@ -519,19 +527,19 @@
     }
 
     private void onLegacyTargetSelected(AccessibilityButtonTarget target) {
-        if (mShortcutType == ACCESSIBILITY_BUTTON) {
+        if (sShortcutType == ACCESSIBILITY_BUTTON) {
             final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
             ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
-        } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+        } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
             switchServiceState(target);
         }
     }
 
     private void onInvisibleTargetSelected(AccessibilityButtonTarget target) {
         final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
-        if (mShortcutType == ACCESSIBILITY_BUTTON) {
+        if (sShortcutType == ACCESSIBILITY_BUTTON) {
             ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
-        } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+        } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
             ams.performAccessibilityShortcut(target.getId());
         }
     }
@@ -542,9 +550,9 @@
 
     private void onBounceTargetSelected(AccessibilityButtonTarget target) {
         final AccessibilityManager ams = getSystemService(AccessibilityManager.class);
-        if (mShortcutType == ACCESSIBILITY_BUTTON) {
+        if (sShortcutType == ACCESSIBILITY_BUTTON) {
             ams.notifyAccessibilityButtonClicked(getDisplayId(), target.getId());
-        } else if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+        } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
             ams.performAccessibilityShortcut(target.getId());
         }
     }
@@ -565,66 +573,101 @@
         }
     }
 
-    private void onTargetDeleted(AdapterView<?> parent, View view, int position, long id) {
-        final AccessibilityButtonTarget target = mTargets.get(position);
-        final String componentId = target.getId();
+    private void onTargetChecked(AdapterView<?> parent, View view, int position, long id) {
+        mCurrentCheckedTarget = mTargets.get(position);
 
+        if ((mCurrentCheckedTarget.getType() == TargetType.ACCESSIBILITY_SERVICE)
+                && !mCurrentCheckedTarget.isChecked()) {
+            mEnableDialog = new AlertDialog.Builder(this)
+                    .setView(createEnableDialogContentView(this, mCurrentCheckedTarget,
+                            this::onPermissionAllowButtonClicked,
+                            this::onPermissionDenyButtonClicked))
+                    .create();
+            mEnableDialog.show();
+            return;
+        }
+
+        onTargetChecked(mCurrentCheckedTarget, !mCurrentCheckedTarget.isChecked());
+    }
+
+    private void onTargetChecked(AccessibilityButtonTarget target, boolean checked) {
         switch (target.getFragmentType()) {
             case AccessibilityServiceFragmentType.LEGACY:
-                onLegacyTargetDeleted(position, componentId);
+                onLegacyTargetChecked(checked);
                 break;
             case AccessibilityServiceFragmentType.INVISIBLE:
-                onInvisibleTargetDeleted(position, componentId);
+                onInvisibleTargetChecked(checked);
                 break;
             case AccessibilityServiceFragmentType.INTUITIVE:
-                onIntuitiveTargetDeleted(position, componentId);
+                onIntuitiveTargetChecked(checked);
                 break;
             case AccessibilityServiceFragmentType.BOUNCE:
-                onBounceTargetDeleted(position, componentId);
+                onBounceTargetChecked(checked);
                 break;
             default:
                 throw new IllegalStateException("Unexpected fragment type");
         }
+    }
 
+    private void onLegacyTargetChecked(boolean checked) {
+        if (sShortcutType == ACCESSIBILITY_BUTTON) {
+            setServiceEnabled(mCurrentCheckedTarget.getId(), checked);
+            if (!checked) {
+                optOutValueFromSettings(this, HARDWARE, mCurrentCheckedTarget.getId());
+                final String warningText =
+                        getString(R.string.accessibility_uncheck_legacy_item_warning,
+                                mCurrentCheckedTarget.getLabel());
+                Toast.makeText(this, warningText, Toast.LENGTH_SHORT).show();
+            }
+        } else if (sShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
+            updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+        } else {
+            throw new IllegalStateException("Unexpected shortcut type");
+        }
+
+        mCurrentCheckedTarget.setChecked(checked);
+        mTargetAdapter.notifyDataSetChanged();
+    }
+
+    private void onInvisibleTargetChecked(boolean checked) {
+        final int shortcutTypes = UserShortcutType.SOFTWARE | HARDWARE;
+        if (!hasValuesInSettings(this, shortcutTypes, mCurrentCheckedTarget.getId())) {
+            setServiceEnabled(mCurrentCheckedTarget.getId(), checked);
+        }
+
+        updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+        mCurrentCheckedTarget.setChecked(checked);
+        mTargetAdapter.notifyDataSetChanged();
+    }
+
+    private void onIntuitiveTargetChecked(boolean checked) {
+        updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+        mCurrentCheckedTarget.setChecked(checked);
+        mTargetAdapter.notifyDataSetChanged();
+    }
+
+    private void onBounceTargetChecked(boolean checked) {
+        updateValueToSettings(mCurrentCheckedTarget.getId(), checked);
+        mCurrentCheckedTarget.setChecked(checked);
+        mTargetAdapter.notifyDataSetChanged();
+    }
+
+    private void updateValueToSettings(String componentId, boolean checked) {
+        if (checked) {
+            optInValueToSettings(this, mShortcutUserType, componentId);
+        } else  {
+            optOutValueFromSettings(this, mShortcutUserType, componentId);
+        }
+    }
+
+    private void onDoneButtonClicked() {
+        mTargets.clear();
+        mTargets.addAll(getServiceTargets(this, sShortcutType));
         if (mTargets.isEmpty()) {
             mAlertDialog.dismiss();
-        }
-    }
-
-    private void onLegacyTargetDeleted(int position, String componentId) {
-        if (mShortcutType == ACCESSIBILITY_SHORTCUT_KEY) {
-            optOutValueFromSettings(this, mShortcutUserType, componentId);
-
-            mTargets.remove(position);
-            mTargetAdapter.notifyDataSetChanged();
-        }
-    }
-
-    private void onInvisibleTargetDeleted(int position, String componentId) {
-        optOutValueFromSettings(this, mShortcutUserType, componentId);
-
-        final int shortcutTypes = UserShortcutType.SOFTWARE | UserShortcutType.HARDWARE;
-        if (!hasValuesInSettings(this, shortcutTypes, componentId)) {
-            disableService(componentId);
+            return;
         }
 
-        mTargets.remove(position);
-        mTargetAdapter.notifyDataSetChanged();
-    }
-
-    private void onIntuitiveTargetDeleted(int position, String componentId) {
-        optOutValueFromSettings(this, mShortcutUserType, componentId);
-        mTargets.remove(position);
-        mTargetAdapter.notifyDataSetChanged();
-    }
-
-    private void onBounceTargetDeleted(int position, String componentId) {
-        optOutValueFromSettings(this, mShortcutUserType, componentId);
-        mTargets.remove(position);
-        mTargetAdapter.notifyDataSetChanged();
-    }
-
-    private void onCancelButtonClicked() {
         mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.LAUNCH);
         mTargetAdapter.notifyDataSetChanged();
 
@@ -635,11 +678,13 @@
     }
 
     private void onEditButtonClicked() {
+        mTargets.clear();
+        mTargets.addAll(getInstalledServiceTargets(this));
         mTargetAdapter.setShortcutMenuMode(ShortcutMenuMode.EDIT);
         mTargetAdapter.notifyDataSetChanged();
 
         mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setText(
-                getString(R.string.cancel_accessibility_shortcut_menu_button));
+                getString(R.string.done_accessibility_shortcut_menu_button));
 
         updateDialogListeners();
     }
@@ -649,15 +694,78 @@
                 (mTargetAdapter.getShortcutMenuMode() == ShortcutMenuMode.EDIT);
         final int selectDialogTitleId = R.string.accessibility_select_shortcut_menu_title;
         final int editDialogTitleId =
-                (mShortcutType == ACCESSIBILITY_BUTTON)
+                (sShortcutType == ACCESSIBILITY_BUTTON)
                         ? R.string.accessibility_edit_shortcut_menu_button_title
                         : R.string.accessibility_edit_shortcut_menu_volume_title;
 
         mAlertDialog.setTitle(getString(isEditMenuMode ? editDialogTitleId : selectDialogTitleId));
-
         mAlertDialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(
-                isEditMenuMode ? view -> onCancelButtonClicked() : view -> onEditButtonClicked());
+                isEditMenuMode ? view -> onDoneButtonClicked() : view -> onEditButtonClicked());
         mAlertDialog.getListView().setOnItemClickListener(
-                isEditMenuMode ? this::onTargetDeleted : this::onTargetSelected);
+                isEditMenuMode ? this::onTargetChecked : this::onTargetSelected);
+    }
+
+    private static boolean isTargetShortcutUsed(@NonNull Context context, String id) {
+        final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class);
+        final List<String> requiredTargets = ams.getAccessibilityShortcutTargets(sShortcutType);
+        return requiredTargets.contains(id);
+    }
+
+    private void onPermissionAllowButtonClicked(View view) {
+        if (mCurrentCheckedTarget.getFragmentType() != AccessibilityServiceFragmentType.LEGACY) {
+            updateValueToSettings(mCurrentCheckedTarget.getId(), /* checked= */ true);
+        }
+        onTargetChecked(mCurrentCheckedTarget, /* checked= */ true);
+        mEnableDialog.dismiss();
+    }
+
+    private void onPermissionDenyButtonClicked(View view) {
+        mEnableDialog.dismiss();
+    }
+
+    private static View createEnableDialogContentView(Context context,
+            AccessibilityButtonTarget target, View.OnClickListener allowListener,
+            View.OnClickListener denyListener) {
+        final LayoutInflater inflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
+
+        final View content = inflater.inflate(
+                R.layout.accessibility_enable_service_encryption_warning, /* root= */ null);
+
+        final TextView encryptionWarningView = (TextView) content.findViewById(
+                R.id.accessibility_encryption_warning);
+        if (StorageManager.isNonDefaultBlockEncrypted()) {
+            final String text = context.getString(
+                    R.string.accessibility_enable_service_encryption_warning,
+                    getServiceName(context, target.getLabel()));
+            encryptionWarningView.setText(text);
+            encryptionWarningView.setVisibility(View.VISIBLE);
+        } else {
+            encryptionWarningView.setVisibility(View.GONE);
+        }
+
+        final ImageView permissionDialogIcon = content.findViewById(
+                R.id.accessibility_permissionDialog_icon);
+        permissionDialogIcon.setImageDrawable(target.getDrawable());
+
+        final TextView permissionDialogTitle = content.findViewById(
+                R.id.accessibility_permissionDialog_title);
+        permissionDialogTitle.setText(context.getString(R.string.accessibility_enable_service_title,
+                getServiceName(context, target.getLabel())));
+
+        final Button permissionAllowButton = content.findViewById(
+                R.id.accessibility_permission_enable_allow_button);
+        final Button permissionDenyButton = content.findViewById(
+                R.id.accessibility_permission_enable_deny_button);
+        permissionAllowButton.setOnClickListener(allowListener);
+        permissionDenyButton.setOnClickListener(denyListener);
+
+        return content;
+    }
+
+    // Gets the service name and bidi wrap it to protect from bidi side effects.
+    private static CharSequence getServiceName(Context context, CharSequence label) {
+        final Locale locale = context.getResources().getConfiguration().getLocales().get(0);
+        return BidiFormatter.getInstance(locale).unicodeWrap(label);
     }
 }
diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java
index bed41b3..9a78ad2 100644
--- a/core/java/com/android/internal/compat/OverrideAllowedState.java
+++ b/core/java/com/android/internal/compat/OverrideAllowedState.java
@@ -50,7 +50,7 @@
     public static final int DISABLED_NOT_DEBUGGABLE = 1;
     /**
      * Change cannot be overridden, due to the build being non-debuggable and the change being
-     * non-targetSdk.
+     * enabled regardless of targetSdk.
      */
     public static final int DISABLED_NON_TARGET_SDK = 2;
     /**
@@ -159,4 +159,28 @@
                 && appTargetSdk == otherState.appTargetSdk
                 && changeIdTargetSdk == otherState.changeIdTargetSdk;
     }
+
+    private String stateName() {
+        switch (state) {
+            case ALLOWED:
+                return "ALLOWED";
+            case DISABLED_NOT_DEBUGGABLE:
+                return "DISABLED_NOT_DEBUGGABLE";
+            case DISABLED_NON_TARGET_SDK:
+                return "DISABLED_NON_TARGET_SDK";
+            case DISABLED_TARGET_SDK_TOO_HIGH:
+                return "DISABLED_TARGET_SDK_TOO_HIGH";
+            case PACKAGE_DOES_NOT_EXIST:
+                return "PACKAGE_DOES_NOT_EXIST";
+            case LOGGING_ONLY_CHANGE:
+                return "LOGGING_ONLY_CHANGE";
+        }
+        return "UNKNOWN";
+    }
+
+    @Override
+    public String toString() {
+        return "OverrideAllowedState(state=" + stateName() + "; appTargetSdk=" + appTargetSdk
+                + "; changeIdTargetSdk=" + changeIdTargetSdk + ")";
+    }
 }
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
index 85643fc..c90d8512 100644
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ b/core/java/com/android/internal/logging/InstanceId.java
@@ -48,6 +48,17 @@
         return mId;
     }
 
+    /**
+     * Create a fake instance ID for testing purposes.  Not for production use. See also
+     * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
+     * @param id The ID you want to assign.
+     * @return new InstanceId.
+     */
+    @VisibleForTesting
+    public static InstanceId fakeInstanceId(int id) {
+        return new InstanceId(id);
+    }
+
     @Override
     public int hashCode() {
         return mId;
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index f8c0d9e..fdcc8a8 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -29,6 +29,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.regex.Matcher;
@@ -99,7 +100,7 @@
     }
 
     @Override
-    public void onChange(boolean selfChange, Uri uri, int userId) {
+    public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
         updateReader();
     }
 
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index bf796cd..28994fd 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -28,6 +28,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 
+import java.util.Collection;
 import java.util.Objects;
 
 /**
@@ -77,8 +78,8 @@
     private final ContentObserver mSmsContentObserver = new ContentObserver(
             new Handler(Looper.getMainLooper())) {
         @Override
-        public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
+        public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+            if (uris.contains(Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING))) {
                 cacheDefaultSmsApp(userId);
             }
         }
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3378c07..d40924b 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -82,6 +82,9 @@
     // property for runtime configuration differentiation
     private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku";
 
+    // property for runtime configuration differentiation in vendor
+    private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
+
     // Group-ids that are given to all packages as read from etc/permissions/*.xml.
     int[] mGlobalGids;
 
@@ -468,6 +471,17 @@
         readPermissions(Environment.buildPath(
                 Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
 
+        String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
+        if (!vendorSkuProperty.isEmpty()) {
+            String vendorSkuDir = "sku_" + vendorSkuProperty;
+            readPermissions(Environment.buildPath(
+                    Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
+                    vendorPermissionFlag);
+            readPermissions(Environment.buildPath(
+                    Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
+                    vendorPermissionFlag);
+        }
+
         // Allow ODM to customize system configs as much as Vendor, because /odm is another
         // vendor partition other than /vendor.
         int odmPermissionFlag = vendorPermissionFlag;
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 4e139a3..2128f99 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -134,6 +134,11 @@
 static bool gIsSecurityEnforced = true;
 
 /**
+ * True if the app process is running in its mount namespace.
+ */
+static bool gInAppMountNamespace = false;
+
+/**
  * The maximum number of characters (not including a null terminator) that a
  * process name may contain.
  */
@@ -548,6 +553,17 @@
   }
 }
 
+static void ensureInAppMountNamespace(fail_fn_t fail_fn) {
+  if (gInAppMountNamespace) {
+    // In app mount namespace already
+    return;
+  }
+  if (unshare(CLONE_NEWNS) == -1) {
+    fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
+  }
+  gInAppMountNamespace = true;
+}
+
 // Sets the resource limits via setrlimit(2) for the values in the
 // two-dimensional array of integers that's passed in. The second dimension
 // contains a tuple of length 3: (resource, rlim_cur, rlim_max). nullptr is
@@ -811,9 +827,7 @@
   }
 
   // Create a second private mount namespace for our process
-  if (unshare(CLONE_NEWNS) == -1) {
-    fail_fn(CREATE_ERROR("Failed to unshare(): %s", strerror(errno)));
-  }
+  ensureInAppMountNamespace(fail_fn);
 
   // Handle force_mount_namespace with MOUNT_EXTERNAL_NONE.
   if (mount_mode == MOUNT_EXTERNAL_NONE) {
@@ -1319,6 +1333,7 @@
   if ((size % 3) != 0) {
     fail_fn(CREATE_ERROR("Wrong pkg_inode_list size %d", size));
   }
+  ensureInAppMountNamespace(fail_fn);
 
   // Mount tmpfs on all possible data directories, so app no longer see the original apps data.
   char internalCePath[PATH_MAX];
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index b4f3d1e..22f2498 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -40,6 +40,7 @@
     ENABLE_DISABLE_REASON_CRASH = 7;
     ENABLE_DISABLE_REASON_USER_SWITCH = 8;
     ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
+    ENABLE_DISABLE_REASON_FACTORY_RESET = 10;
 }
 
 enum DirectionEnum {
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index e8a0b46..608925578 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -53,10 +53,10 @@
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional WindowContainerProto window_container = 1;
-    repeated DisplayContentProto displays = 2;
+    repeated DisplayContentProto displays = 2 [deprecated=true];
     reserved 3; // IdentifierProto windows
     /* window references in top down z order */
-    repeated WindowStateProto windows = 4;
+    repeated WindowStateProto windows = 4 [deprecated=true];
     optional KeyguardControllerProto keyguard_controller = 5;
     // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
     // know what activity types to check for when invoking splitscreen multi-window.
@@ -192,7 +192,8 @@
     optional bool single_task_instance = 22;
     optional int32 focused_root_task_id = 23;
     optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
-    repeated TaskProto tasks = 25;
+    repeated TaskProto tasks = 25 [deprecated=true];
+    optional bool display_ready = 26;
 }
 
 /* represents DisplayArea object */
@@ -201,7 +202,7 @@
 
     optional WindowContainerProto window_container = 1;
     optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
-    repeated DisplayAreaChildProto children = 3;
+    repeated DisplayAreaChildProto children = 3 [deprecated=true];
 }
 
 /* represents a generic child of a DisplayArea */
@@ -254,8 +255,8 @@
     optional int32 surface_width = 8;
     optional int32 surface_height = 9;
 
-    repeated TaskProto tasks = 10;
-    repeated ActivityRecordProto activities = 11;
+    repeated TaskProto tasks = 10 [deprecated=true];
+    repeated ActivityRecordProto activities = 11 [deprecated=true];
 
     optional .com.android.server.wm.IdentifierProto resumed_activity = 12;
     optional string real_activity = 13;
@@ -321,7 +322,7 @@
 
     optional WindowContainerProto window_container = 1;
     optional int32 hash_code = 2;
-    repeated WindowStateProto windows = 3;
+    repeated WindowStateProto windows = 3 [deprecated=true];
     optional bool waiting_to_show = 5;
     optional bool paused = 6;
 }
@@ -346,7 +347,7 @@
     optional .android.graphics.RectProto surface_insets = 12;
     optional WindowStateAnimatorProto animator = 13;
     optional bool animating_exit = 14;
-    repeated WindowStateProto child_windows = 15;
+    repeated WindowStateProto child_windows = 15 [deprecated=true];
     optional .android.graphics.RectProto surface_position = 16;
     optional int32 requested_width = 18;
     optional int32 requested_height = 19;
@@ -426,6 +427,32 @@
     optional int32 orientation = 2;
     optional bool visible = 3;
     optional SurfaceAnimatorProto surface_animator = 4;
+    repeated WindowContainerChildProto children = 5;
+}
+
+/* represents a generic child of a WindowContainer */
+message WindowContainerChildProto {
+    option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+    /* A window container can have multiple children of different types stored as
+     * a WindowContainerChildProto but each instance of WindowContainerChildProto
+     * can only contain a single type.
+     */
+    /* We do not know the derived typ and the class is dumped
+     * as a WindowContainer */
+    optional WindowContainerProto window_container = 2;
+    /* represents a DisplayContent child */
+    optional DisplayContentProto display_content = 3;
+    /* represents a DisplayArea child */
+    optional DisplayAreaProto display_area = 4;
+    /* represents a Task child */
+    optional TaskProto task = 5;
+    /* represents an ActivityRecord child */
+    optional ActivityRecordProto activity = 6;
+    /* represents a WindowToken child */
+    optional WindowTokenProto window_token = 7;
+    /* represents a WindowState child */
+    optional WindowStateProto window = 8;
 }
 
 /* represents ConfigurationContainer */
diff --git a/core/proto/android/view/remote_animation_target.proto b/core/proto/android/view/remote_animation_target.proto
index 24d2785..150493d 100644
--- a/core/proto/android/view/remote_animation_target.proto
+++ b/core/proto/android/view/remote_animation_target.proto
@@ -44,4 +44,6 @@
     optional .android.app.WindowConfigurationProto window_configuration = 10;
     optional .android.view.SurfaceControlProto start_leash = 11;
     optional .android.graphics.RectProto start_bounds = 12;
+    optional .android.graphics.RectProto local_bounds = 13;
+    optional .android.graphics.RectProto screen_space_bounds = 14;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8851170..dac6576 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1305,7 +1305,7 @@
         android:description="@string/permdesc_camera"
         android:protectionLevel="dangerous|instant" />
 
-      <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
+    <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
            system only camera devices.
            <p>Protection level: system|signature
            @hide -->
@@ -1315,6 +1315,15 @@
         android:description="@string/permdesc_systemCamera"
         android:protectionLevel="system|signature" />
 
+    <!-- Allows receiving the camera service notifications when a camera is opened
+            (by a certain application package) or closed.
+        @hide -->
+    <permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER"
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_cameraOpenCloseListener"
+        android:description="@string/permdesc_cameraOpenCloseListener"
+        android:protectionLevel="signature" />
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device sensors                           -->
     <!-- ====================================================================== -->
@@ -3726,7 +3735,8 @@
     <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
                 android:protectionLevel="signature|installer" />
 
-    <!-- @hide Allows an application to upgrade runtime permissions. -->
+    <!-- @SystemApi @TestApi Allows an application to upgrade runtime permissions.
+    @hide -->
     <permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS"
                 android:protectionLevel="signature" />
 
diff --git a/core/res/res/drawable/ic_delete_item.xml b/core/res/res/drawable/ic_pan_tool.xml
similarity index 69%
copy from core/res/res/drawable/ic_delete_item.xml
copy to core/res/res/drawable/ic_pan_tool.xml
index 8a398a4..c1a8549 100644
--- a/core/res/res/drawable/ic_delete_item.xml
+++ b/core/res/res/drawable/ic_pan_tool.xml
@@ -12,7 +12,7 @@
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-  -->
+-->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
@@ -21,6 +21,6 @@
     android:viewportHeight="24"
     android:tint="?attr/colorControlNormal">
   <path
-      android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
+      android:pathData="M23,5.5V20c0,2.2 -1.8,4 -4,4h-7.3c-1.08,0 -2.1,-0.43 -2.85,-1.19L1,14.83c0,0 1.26,-1.23 1.3,-1.25c0.22,-0.19 0.49,-0.29 0.79,-0.29c0.22,0 0.42,0.06 0.6,0.16C3.73,13.46 8,15.91 8,15.91V4c0,-0.83 0.67,-1.5 1.5,-1.5S11,3.17 11,4v7h1V1.5C12,0.67 12.67,0 13.5,0S15,0.67 15,1.5V11h1V2.5C16,1.67 16.67,1 17.5,1S19,1.67 19,2.5V11h1V5.5C20,4.67 20.67,4 21.5,4S23,4.67 23,5.5z"
       android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/core/res/res/drawable/ic_delete_item.xml b/core/res/res/drawable/ic_visibility.xml
similarity index 77%
rename from core/res/res/drawable/ic_delete_item.xml
rename to core/res/res/drawable/ic_visibility.xml
index 8a398a4..1956241 100644
--- a/core/res/res/drawable/ic_delete_item.xml
+++ b/core/res/res/drawable/ic_visibility.xml
@@ -12,7 +12,7 @@
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-  -->
+-->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="24dp"
@@ -21,6 +21,6 @@
     android:viewportHeight="24"
     android:tint="?attr/colorControlNormal">
   <path
-      android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
+      android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"
       android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/core/res/res/layout/accessibility_button_chooser_item.xml b/core/res/res/layout/accessibility_button_chooser_item.xml
index c01766b..b7dd892 100644
--- a/core/res/res/layout/accessibility_button_chooser_item.xml
+++ b/core/res/res/layout/accessibility_button_chooser_item.xml
@@ -21,10 +21,17 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:gravity="center"
-    android:paddingStart="16dp"
-    android:paddingEnd="16dp"
-    android:paddingTop="12dp"
-    android:paddingBottom="12dp">
+    android:padding="16dp">
+
+    <CheckBox
+        android:id="@+id/accessibility_button_target_checkbox"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="16dp"
+        android:background="@null"
+        android:clickable="false"
+        android:focusable="false"
+        android:visibility="gone"/>
 
     <ImageView
         android:id="@+id/accessibility_button_target_icon"
@@ -36,31 +43,18 @@
         android:id="@+id/accessibility_button_target_label"
         android:layout_width="0dp"
         android:layout_height="wrap_content"
-        android:layout_marginStart="14dp"
+        android:layout_marginStart="16dp"
         android:layout_weight="1"
         android:textSize="20sp"
         android:textColor="?attr/textColorPrimary"
         android:fontFamily="sans-serif-medium"/>
 
-    <FrameLayout
-        android:id="@+id/accessibility_button_target_item_container"
+    <Switch
+        android:id="@+id/accessibility_button_target_switch_item"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:minWidth="56dp">
-
-        <ImageView
-            android:id="@+id/accessibility_button_target_view_item"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"/>
-
-        <Switch android:id="@+id/accessibility_button_target_switch_item"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                android:background="@null"
-                android:clickable="false"
-                android:focusable="false"/>
-    </FrameLayout>
+        android:background="@null"
+        android:clickable="false"
+        android:focusable="false"/>
 </LinearLayout>
 
diff --git a/core/res/res/layout/accessibility_enable_service_encryption_warning.xml b/core/res/res/layout/accessibility_enable_service_encryption_warning.xml
new file mode 100644
index 0000000..4000516
--- /dev/null
+++ b/core/res/res/layout/accessibility_enable_service_encryption_warning.xml
@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<ScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textDirection="locale"
+    android:scrollbarStyle="outsideOverlay">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingStart="24dp"
+            android:paddingEnd="24dp"
+            android:gravity="center"
+            android:orientation="vertical">
+
+            <ImageView
+                android:id="@+id/accessibility_permissionDialog_icon"
+                android:layout_width="36dp"
+                android:layout_height="36dp"
+                android:layout_marginTop="16dp"
+                android:layout_marginBottom="16dp"
+                android:scaleType="fitCenter"/>
+
+            <TextView
+                android:id="@+id/accessibility_permissionDialog_title"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:textSize="20sp"
+                android:textColor="?android:attr/textColorPrimary"
+                android:fontFamily="google-sans-medium"/>
+
+            <TextView
+                android:id="@+id/accessibility_encryption_warning"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="10dip"
+                android:textAlignment="viewStart"
+                android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+            <TextView
+                android:id="@+id/accessibility_permissionDialog_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="16dp"
+                android:layout_marginBottom="32dp"
+                android:text="@string/accessibility_service_warning_description"
+                android:textSize="16sp"
+                android:textColor="?android:attr/textColorPrimary"
+                android:fontFamily="sans-serif"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <ImageView
+                    android:id="@+id/accessibility_controlScreen_icon"
+                    android:layout_width="18dp"
+                    android:layout_height="18dp"
+                    android:layout_marginRight="12dp"
+                    android:src="@android:drawable/ic_visibility"
+                    android:scaleType="fitCenter"/>
+
+                <TextView
+                    android:id="@+id/accessibility_controlScreen_title"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:text="@string/accessibility_service_screen_control_title"
+                    android:textSize="16sp"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:fontFamily="sans-serif"/>
+            </LinearLayout>
+
+            <TextView
+                android:id="@+id/accessibility_controlScreen_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="24dp"
+                android:paddingStart="30dp"
+                android:text="@string/accessibility_service_screen_control_description"
+                android:textSize="14sp"
+                android:textColor="?android:attr/textColorSecondary"
+                android:fontFamily="sans-serif"/>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:orientation="horizontal">
+
+                <ImageView
+                    android:id="@+id/accessibility_performAction_icon"
+                    android:layout_width="18dp"
+                    android:layout_height="18dp"
+                    android:layout_marginEnd="12dp"
+                    android:src="@android:drawable/ic_pan_tool"
+                    android:scaleType="fitCenter"/>
+
+                <TextView
+                    android:id="@+id/accessibility_performAction_title"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:text="@string/accessibility_service_action_perform_title"
+                    android:textSize="16sp"
+                    android:textColor="?android:attr/textColorPrimary"
+                    android:fontFamily="sans-serif"/>
+            </LinearLayout>
+
+            <TextView
+                android:id="@+id/accessibility_performAction_description"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="24dp"
+                android:paddingStart="30dp"
+                android:text="@string/accessibility_service_action_perform_description"
+                android:textSize="14sp"
+                android:textColor="?android:attr/textColorSecondary"
+                android:fontFamily="sans-serif" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/chooser_row_divider"/>
+
+        <Button
+            android:id="@+id/accessibility_permission_enable_allow_button"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:background="?android:attr/selectableItemBackground"
+            android:text="@string/accessibility_dialog_button_allow"
+            style="?attr/buttonBarPositiveButtonStyle"/>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/chooser_row_divider"/>
+
+        <Button
+            android:id="@+id/accessibility_permission_enable_deny_button"
+            android:layout_width="match_parent"
+            android:layout_height="56dp"
+            android:background="?android:attr/selectableItemBackground"
+            android:text="@string/accessibility_dialog_button_deny"
+            style="?attr/buttonBarPositiveButtonStyle"/>
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index caec9ed..632c400 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1631,12 +1631,9 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string>
-    <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
-    <skip />
+    <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Tik op die toeganklikheidprogram wat jy wil gebruik"</string>
+    <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Kies programme wat jy met toeganklikheidknoppie wil gebruik"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Kies programme wat jy met die volumesleutelkortpad wil gebruik"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Wysig kortpaaie"</string>
     <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Kanselleer"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Skakel kortpad af"</string>
@@ -2033,29 +2030,19 @@
     <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
     <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlik"</string>
     <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string>
-    <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
-    <skip />
-    <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
-    <skip />
+    <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persoonlike aansig"</string>
+    <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Werkaansig"</string>
     <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Kan nie met werkprogramme deel nie"</string>
     <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Kan nie met persoonlike programme deel nie"</string>
-    <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
-    <skip />
+    <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Jou IT-admin het deling tussen persoonlike en werkprofiele geblokkeer"</string>
+    <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Kan nie toegang tot werkprogramme kry nie"</string>
+    <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Jou IT-admin laat jou nie toe om persoonlike inhoud in werkprogramme te bekyk nie"</string>
+    <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Kan nie toegang tot persoonlike programme kry nie"</string>
+    <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Jou IT-admin laat jou nie toe om werkinhoud in persoonlike programme te bekyk nie"</string>
+    <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Skakel werkprofiel aan om inhoud te deel"</string>
+    <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Skakel werkprofiel aan om inhoud te bekyk"</string>
     <string name="resolver_no_apps_available" msgid="7710339903040989654">"Geen programme beskikbaar nie"</string>
-    <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
-    <skip />
+    <string name="resolver_switch_on_work" msgid="2873009160846966379">"Skakel aan"</string>
     <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Neem oudio in telefonie-oproepe op of speel dit"</string>
     <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Laat hierdie program, indien dit as die verstekbellerprogram aangewys is, toe om oudio in telefonie-oproepe op te neem of te speel."</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 63497aa..1a7f301 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1631,12 +1631,9 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"推奨レベルを超えるまで音量を上げますか?\n\n大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"ユーザー補助機能のショートカットの使用"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string>
-    <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
-    <skip />
+    <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"使用するユーザー補助アプリをタップ"</string>
+    <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"ユーザー補助機能ボタンで使用できるアプリを選択"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"音量キーのショートカットで使用できるアプリを選択"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ショートカットの編集"</string>
     <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"キャンセル"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"ショートカットを OFF にする"</string>
@@ -2033,29 +2030,19 @@
     <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
     <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string>
     <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string>
-    <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
-    <skip />
-    <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
-    <skip />
+    <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人用ビュー"</string>
+    <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"仕事用ビュー"</string>
     <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"仕事用アプリと共有できません"</string>
     <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"個人用アプリと共有できません"</string>
-    <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
-    <skip />
+    <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"IT 管理者が個人用プロファイルと仕事用プロファイルの間の共有をブロックしました"</string>
+    <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"仕事用アプリにアクセスできません"</string>
+    <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"IT 管理者は個人用コンテンツを仕事用アプリで表示することを許可していません"</string>
+    <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"個人用アプリにアクセスできません"</string>
+    <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"IT 管理者は仕事用コンテンツを個人用アプリで表示することを許可していません"</string>
+    <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"コンテンツを共有するには、仕事用プロファイルをオンにしてください"</string>
+    <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"コンテンツを表示するには、仕事用プロファイルをオンにしてください"</string>
     <string name="resolver_no_apps_available" msgid="7710339903040989654">"利用できるアプリはありません"</string>
-    <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
-    <skip />
+    <string name="resolver_switch_on_work" msgid="2873009160846966379">"オンにする"</string>
     <string name="permlab_accessCallAudio" msgid="1682957511874097664">"通話中に録音または音声の再生を行う"</string>
     <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"デフォルトの電話アプリケーションとして割り当てられている場合、このアプリに通話中の録音または音声の再生を許可します。"</string>
 </resources>
diff --git a/core/res/res/values-mcc219/config.xml b/core/res/res/values-mcc219/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc219/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources>
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array name="config_twoDigitNumberPattern">
-        <item>"92"</item>
-        <item>"93"</item>
-        <item>"94"</item>
-        <item>"95"</item>
-        <item>"96"</item>
-    </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc220/config.xml b/core/res/res/values-mcc220/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc220/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources>
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array name="config_twoDigitNumberPattern">
-        <item>"92"</item>
-        <item>"93"</item>
-        <item>"94"</item>
-        <item>"95"</item>
-        <item>"96"</item>
-    </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
deleted file mode 100644
index e7d1325..0000000
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string-array translatable="false" name="config_twoDigitNumberPattern">
-        <item>"0"</item>
-        <item>"00"</item>
-        <item>"*0"</item>
-        <item>"*1"</item>
-        <item>"*2"</item>
-        <item>"*3"</item>
-        <item>"*4"</item>
-        <item>"*5"</item>
-        <item>"*6"</item>
-        <item>"*7"</item>
-        <item>"*8"</item>
-        <item>"*9"</item>
-        <item>"#0"</item>
-        <item>"#1"</item>
-        <item>"#2"</item>
-        <item>"#3"</item>
-        <item>"#4"</item>
-        <item>"#5"</item>
-        <item>"#6"</item>
-        <item>"#7"</item>
-        <item>"#8"</item>
-        <item>"#9"</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index 3fb3f0f..53e4193 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -23,31 +23,6 @@
     <!-- Configure mobile network MTU. Carrier specific value is set here.
     -->
     <integer name="config_mobile_mtu">1410</integer>
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array name="config_twoDigitNumberPattern">
-        <item>"0"</item>
-        <item>"00"</item>
-        <item>"*0"</item>
-        <item>"*1"</item>
-        <item>"*2"</item>
-        <item>"*3"</item>
-        <item>"*4"</item>
-        <item>"*5"</item>
-        <item>"*6"</item>
-        <item>"*7"</item>
-        <item>"*8"</item>
-        <item>"*9"</item>
-        <item>"#0"</item>
-        <item>"#1"</item>
-        <item>"#2"</item>
-        <item>"#3"</item>
-        <item>"#4"</item>
-        <item>"#5"</item>
-        <item>"#6"</item>
-        <item>"#7"</item>
-        <item>"#8"</item>
-        <item>"#9"</item>
-    </string-array>
 
     <!-- Enable 5 bar signal strength icon -->
     <bool name="config_inflateSignalStrength">true</bool>
diff --git a/core/res/res/values-mcc313-mnc100/config.xml b/core/res/res/values-mcc313-mnc100/config.xml
deleted file mode 100644
index ccd03f1..0000000
--- a/core/res/res/values-mcc313-mnc100/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string-array translatable="false" name="config_twoDigitNumberPattern">
-        <item>"0"</item>
-        <item>"00"</item>
-        <item>"*0"</item>
-        <item>"*1"</item>
-        <item>"*2"</item>
-        <item>"*3"</item>
-        <item>"*4"</item>
-        <item>"*5"</item>
-        <item>"*6"</item>
-        <item>"*7"</item>
-        <item>"*8"</item>
-        <item>"*9"</item>
-        <item>"#0"</item>
-        <item>"#1"</item>
-        <item>"#2"</item>
-        <item>"#3"</item>
-        <item>"#4"</item>
-        <item>"#5"</item>
-        <item>"#6"</item>
-        <item>"#7"</item>
-        <item>"#8"</item>
-        <item>"#9"</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mcc334-mnc050/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
index 23678f1..2e8c504 100644
--- a/core/res/res/values-mcc334-mnc050/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -31,8 +31,4 @@
       <item>9</item>
     </integer-array>
 
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array translatable="false" name="config_twoDigitNumberPattern">
-        <item>"#9"</item>
-    </string-array>
 </resources>
diff --git a/core/res/res/values-mcc334-mnc090/config.xml b/core/res/res/values-mcc334-mnc090/config.xml
deleted file mode 100644
index 1632a42..0000000
--- a/core/res/res/values-mcc334-mnc090/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-
-    <string-array translatable="false" name="config_twoDigitNumberPattern">
-        <item>"#9"</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
deleted file mode 100644
index 10b6470..0000000
--- a/core/res/res/values-mcc704-mnc01/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources>
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-    <string-array name="config_twoDigitNumberPattern">
-        <item>"*1"</item>
-        <item>"*5"</item>
-        <item>"*9"</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
deleted file mode 100755
index 7b7c48d..0000000
--- a/core/res/res/values-mcc708-mnc001/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources>
-    <string-array translatable="false" name="config_twoDigitNumberPattern">
-        <item>"*1"</item>
-        <item>"*5"</item>
-    </string-array>
-</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7b17305..4054a3a 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1631,12 +1631,9 @@
     <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Хүртээмжийн товчлолыг ашиглах уу?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string>
-    <!-- no translation found for accessibility_select_shortcut_menu_title (7310194076629867377) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_button_title (6096484087245145325) -->
-    <skip />
-    <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (4849108668454490699) -->
-    <skip />
+    <string name="accessibility_select_shortcut_menu_title" msgid="7310194076629867377">"Ашиглахыг хүсэж буй хандалтын аппаа товших"</string>
+    <string name="accessibility_edit_shortcut_menu_button_title" msgid="6096484087245145325">"Хандалтын товчлуурын тусламжтай ашиглахыг хүсэж буй аппуудаа сонгох"</string>
+    <string name="accessibility_edit_shortcut_menu_volume_title" msgid="4849108668454490699">"Дууны түвшин тохируулах түлхүүрийн товчлолын тусламжтай ашиглахыг хүсэж буй аппуудаа сонгох"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Товчлолуудыг засах"</string>
     <string name="cancel_accessibility_shortcut_menu_button" msgid="1817413122335452474">"Болих"</string>
     <string name="disable_accessibility_shortcut" msgid="5806091378745232383">"Товчлолыг унтраах"</string>
@@ -2033,29 +2030,19 @@
     <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
     <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string>
     <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string>
-    <!-- no translation found for resolver_personal_tab_accessibility (5739524949153091224) -->
-    <skip />
-    <!-- no translation found for resolver_work_tab_accessibility (4753168230363802734) -->
-    <skip />
+    <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Хувийн харагдах байдал"</string>
+    <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Ажлын харагдах байдал"</string>
     <string name="resolver_cant_share_with_work_apps" msgid="7539495559434146897">"Ажлын аппуудтай хуваалцах боломжгүй"</string>
     <string name="resolver_cant_share_with_personal_apps" msgid="8020581735267157241">"Хувийн аппуудтай хуваалцах боломжгүй"</string>
-    <!-- no translation found for resolver_cant_share_cross_profile_explanation (5556640604460901386) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps (375634344111233790) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_work_apps_explanation (3958762224516867388) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps (1953215925406474177) -->
-    <skip />
-    <!-- no translation found for resolver_cant_access_personal_apps_explanation (1725572276741281136) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_share (619263911204978175) -->
-    <skip />
-    <!-- no translation found for resolver_turn_on_work_apps_view (3073389230905543680) -->
-    <skip />
+    <string name="resolver_cant_share_cross_profile_explanation" msgid="5556640604460901386">"Таны IT админ хувийн болон ажлын профайлуудын хооронд хуваалцахыг блоклосон"</string>
+    <string name="resolver_cant_access_work_apps" msgid="375634344111233790">"Ажлын аппуудад хандах боломжгүй байна"</string>
+    <string name="resolver_cant_access_work_apps_explanation" msgid="3958762224516867388">"Таны IT админ ажлын аппууд дахь хувийн контентыг харахыг танд зөвшөөрөхгүй байна"</string>
+    <string name="resolver_cant_access_personal_apps" msgid="1953215925406474177">"Хувийн аппуудад хандах боломжгүй байна"</string>
+    <string name="resolver_cant_access_personal_apps_explanation" msgid="1725572276741281136">"Таны IT админ хувийн аппууд дахь ажлын контентыг харахыг танд зөвшөөрөхгүй байна"</string>
+    <string name="resolver_turn_on_work_apps_share" msgid="619263911204978175">"Контентыг хуваалцахын тулд ажлын профайлыг асаана уу"</string>
+    <string name="resolver_turn_on_work_apps_view" msgid="3073389230905543680">"Контентыг харахын тулд ажлын профайлыг асаана уу"</string>
     <string name="resolver_no_apps_available" msgid="7710339903040989654">"Боломжтой апп алга байна"</string>
-    <!-- no translation found for resolver_switch_on_work (2873009160846966379) -->
-    <skip />
+    <string name="resolver_switch_on_work" msgid="2873009160846966379">"Асаах"</string>
     <string name="permlab_accessCallAudio" msgid="1682957511874097664">"Утасны дуудлагын үеэр аудио бичих эсвэл тоглуулах"</string>
     <string name="permdesc_accessCallAudio" msgid="8448360894684277823">"Энэ аппыг залгагч өгөгдмөл аппликэйшн болгосон үед түүнд утасны дуудлагын үеэр аудио бичих эсвэл тоглуулахыг зөвшөөрдөг."</string>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0b6e65fe..617949d 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2024,7 +2024,10 @@
          a keyboard is present. -->
     <bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
 
-    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+    <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD.
+
+         Note: This config is deprecated, please use carrier config which is
+               CarrierConfigManager.KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY instead. -->
     <string-array name="config_twoDigitNumberPattern" translatable="false">
     </string-array>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index addcd81..4b49dd3 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1166,6 +1166,11 @@
     <!-- 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_systemCamera">This privileged | system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well</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_cameraOpenCloseListener">Allow an application or service to receive callbacks about camera devices being opened or closed.</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_cameraOpenCloseListener">This signature app can receive callbacks when any camera device is being opened (by what application package) or closed.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibration</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -3402,8 +3407,6 @@
     <!-- A notification is shown when connected network without internet due to private dns validation failed. This is the notification's message. [CHAR LIMIT=NONE] -->
     <string name="private_dns_broken_detailed">Private DNS server cannot be accessed</string>
 
-    <!-- A notification is shown after the user logs in to a captive portal network, to indicate that the network should now have internet connectivity. This is the message of notification. [CHAR LIMIT=50] -->
-    <string name="captive_portal_logged_in_detailed">Connected</string>
     <!-- A notification is shown when the user connects to a network that doesn't have access to some services (e.g. Push notifications may not work). This is the notification's title. [CHAR LIMIT=50] -->
     <string name="network_partial_connectivity"><xliff:g id="network_ssid" example="GoogleGuest">%1$s</xliff:g> has limited connectivity</string>
 
@@ -4403,27 +4406,72 @@
         accessibility feature.
     </string>
 
+    <!-- Title for a warning about security implications of enabling an accessibility
+    service. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_enable_service_title">Allow
+        <xliff:g id="service" example="TalkBack">%1$s</xliff:g> to have full control of your
+        device?</string>
+
+    <!-- Warning that the device data will not be encrypted with password or PIN if
+    enabling an accessibility service and there is a secure lock setup. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_enable_service_encryption_warning">If you turn on
+        <xliff:g id="service" example="TalkBack">%1$s</xliff:g>, your device won’t use your screen
+        lock to enhance data encryption.
+    </string>
+
+    <!-- Warning description that explains that it's appropriate for accessibility
+     services to have full control to help users with accessibility needs. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_service_warning_description">Full control is appropriate for apps
+        that help you with accessibility needs, but not for most apps.
+    </string>
+
+    <!-- Title for the screen control in accessibility dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_service_screen_control_title">View and control screen</string>
+
+    <!-- Description for the screen control in accessibility dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_service_screen_control_description">It can read all content on the
+        screen and display content over other apps.
+    </string>
+
+    <!-- Title for the action perform in accessibility dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_service_action_perform_title">View and perform actions</string>
+
+    <!-- Description for the action perform in accessibility dialog. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_service_action_perform_description">It can track your interactions
+        with an app or a hardware sensor, and interact with apps on your behalf.
+    </string>
+
+    <!-- String for the allow button in accessibility permission dialog. [CHAR LIMIT=10] -->
+    <string name="accessibility_dialog_button_allow">Allow</string>
+    <!-- String for the deny button in accessibility permission dialog. [CHAR LIMIT=10] -->
+    <string name="accessibility_dialog_button_deny">Deny</string>
+
     <!-- Title for accessibility select shortcut menu dialog. [CHAR LIMIT=100] -->
-    <string name="accessibility_select_shortcut_menu_title">Tap the accessibility app you want to use</string>
+    <string name="accessibility_select_shortcut_menu_title">Tap a feature to start using it:</string>
 
     <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered
     from accessibility button. [CHAR LIMIT=100] -->
-    <string name="accessibility_edit_shortcut_menu_button_title">Choose apps you want to use with
+    <string name="accessibility_edit_shortcut_menu_button_title">Choose apps to use with the
         accessibility button
     </string>
 
     <!-- Title for accessibility edit shortcut selection menu dialog, and dialog is triggered
     from volume key shortcut. [CHAR LIMIT=100] -->
-    <string name="accessibility_edit_shortcut_menu_volume_title">Choose apps you want to use with
+    <string name="accessibility_edit_shortcut_menu_volume_title">Choose apps to use with the
         volume key shortcut
     </string>
 
+    <!-- Text for showing the warning to user when uncheck the legacy app item in the accessibility
+    shortcut menu, user can aware the service to be disabled. [CHAR LIMIT=100] -->
+    <string name="accessibility_uncheck_legacy_item_warning">
+        <xliff:g id="service_name" example="TalkBack">%s</xliff:g> has been turned off</string>
+
     <!-- Text in button that edit the accessibility shortcut menu, user can delete
     any service item in the menu list. [CHAR LIMIT=100] -->
     <string name="edit_accessibility_shortcut_menu_button">Edit shortcuts</string>
 
-    <!-- Text in button that cancel the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
-    <string name="cancel_accessibility_shortcut_menu_button">Cancel</string>
+    <!-- Text in button that complete the accessibility shortcut menu changed status. [CHAR LIMIT=100] -->
+    <string name="done_accessibility_shortcut_menu_button">Done</string>
 
     <!-- Text in button that turns off the accessibility shortcut -->
     <string name="disable_accessibility_shortcut">Turn off Shortcut</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 0971aad..826379d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -688,7 +688,6 @@
   <java-symbol type="string" name="capability_title_canControlMagnification" />
   <java-symbol type="string" name="capability_desc_canPerformGestures" />
   <java-symbol type="string" name="capability_title_canPerformGestures" />
-  <java-symbol type="string" name="captive_portal_logged_in_detailed" />
   <java-symbol type="string" name="capital_off" />
   <java-symbol type="string" name="capital_on" />
   <java-symbol type="string" name="cfTemplateForwarded" />
@@ -3240,24 +3239,31 @@
   <java-symbol type="string" name="accessibility_select_shortcut_menu_title" />
   <java-symbol type="string" name="accessibility_edit_shortcut_menu_button_title" />
   <java-symbol type="string" name="accessibility_edit_shortcut_menu_volume_title" />
+  <java-symbol type="string" name="accessibility_uncheck_legacy_item_warning" />
+
+  <java-symbol type="layout" name="accessibility_enable_service_encryption_warning" />
+  <java-symbol type="id" name="accessibility_permissionDialog_icon" />
+  <java-symbol type="id" name="accessibility_permissionDialog_title" />
+  <java-symbol type="id" name="accessibility_encryption_warning" />
+  <java-symbol type="id" name="accessibility_permission_enable_allow_button" />
+  <java-symbol type="id" name="accessibility_permission_enable_deny_button" />
+  <java-symbol type="string" name="accessibility_enable_service_title" />
+  <java-symbol type="string" name="accessibility_enable_service_encryption_warning" />
 
   <!-- Accessibility Button -->
   <java-symbol type="layout" name="accessibility_button_chooser_item" />
+  <java-symbol type="id" name="accessibility_button_target_checkbox" />
   <java-symbol type="id" name="accessibility_button_target_icon" />
   <java-symbol type="id" name="accessibility_button_target_label" />
-  <java-symbol type="id" name="accessibility_button_target_item_container" />
-  <java-symbol type="id" name="accessibility_button_target_view_item" />
   <java-symbol type="id" name="accessibility_button_target_switch_item" />
   <java-symbol type="string" name="accessibility_magnification_chooser_text" />
   <java-symbol type="string" name="edit_accessibility_shortcut_menu_button" />
-  <java-symbol type="string" name="cancel_accessibility_shortcut_menu_button" />
+  <java-symbol type="string" name="done_accessibility_shortcut_menu_button" />
 
   <java-symbol type="drawable" name="ic_accessibility_color_inversion" />
   <java-symbol type="drawable" name="ic_accessibility_color_correction" />
   <java-symbol type="drawable" name="ic_accessibility_magnification" />
 
-  <java-symbol type="drawable" name="ic_delete_item" />
-
   <!-- com.android.internal.widget.RecyclerView -->
   <java-symbol type="id" name="item_touch_helper_previous_elevation"/>
   <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/>
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index c307e64..328429c 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -39,6 +39,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -194,8 +195,8 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri, int userId) {
-            if (mExpectedUri.equals(uri) && mExpectedUserId == userId) {
+        public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+            if (uris.contains(mExpectedUri) && mExpectedUserId == userId) {
                 mLatch.countDown();
             }
         }
diff --git a/core/tests/coretests/src/android/content/ApexContextTest.java b/core/tests/coretests/src/android/content/ApexEnvironmentTest.java
similarity index 75%
rename from core/tests/coretests/src/android/content/ApexContextTest.java
rename to core/tests/coretests/src/android/content/ApexEnvironmentTest.java
index d15c64d..438c5ae 100644
--- a/core/tests/coretests/src/android/content/ApexContextTest.java
+++ b/core/tests/coretests/src/android/content/ApexEnvironmentTest.java
@@ -28,20 +28,21 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ApexContextTest {
+public class ApexEnvironmentTest {
 
     @Test
     public void dataDirectoryPathsAreAsExpected() {
-        ApexContext apexContext = ApexContext.getApexContext("my.apex");
+        ApexEnvironment apexEnvironment = ApexEnvironment.getApexEnvironment("my.apex");
 
         assertEquals("/data/misc/apexdata/my.apex",
-                apexContext.getDeviceProtectedDataDir().getAbsolutePath());
+                apexEnvironment.getDeviceProtectedDataDir().getAbsolutePath());
 
         assertEquals("/data/misc_de/5/apexdata/my.apex",
-                apexContext.getDeviceProtectedDataDirForUser(UserHandle.of(5)).getAbsolutePath());
+                apexEnvironment
+                        .getDeviceProtectedDataDirForUser(UserHandle.of(5)).getAbsolutePath());
 
         assertEquals("/data/misc_ce/16/apexdata/my.apex",
-                apexContext.getCredentialProtectedDataDirForUser(
+                apexEnvironment.getCredentialProtectedDataDirForUser(
                         UserHandle.of(16)).getAbsolutePath());
     }
 }
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index d98ceaf..c0325ca 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -23,7 +23,10 @@
 import static android.os.Environment.classifyExternalStorageDirectory;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import android.app.AppOpsManager;
 import android.content.Context;
 
 import androidx.test.InstrumentationRegistry;
@@ -40,10 +43,33 @@
 public class EnvironmentTest {
     private File dir;
 
-    private Context getContext() {
+    private static Context getContext() {
         return InstrumentationRegistry.getContext();
     }
 
+    /**
+     * Sets {@code mode} for the given {@code ops} and the given {@code uid}.
+     *
+     * <p>This method drops shell permission identity.
+     */
+    private static void setAppOpsModeForUid(int uid, int mode, String... ops) {
+        if (ops == null) {
+            return;
+        }
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity();
+        try {
+            for (String op : ops) {
+                getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+            }
+        } finally {
+            InstrumentationRegistry.getInstrumentation()
+                    .getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
+    }
+
     @Before
     public void setUp() throws Exception {
         dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -101,4 +127,17 @@
         Environment.buildPath(dir, "Taxes.pdf").createNewFile();
         assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
     }
+
+    @Test
+    public void testIsExternalStorageManager() throws Exception {
+        assertFalse(Environment.isExternalStorageManager());
+        try {
+            setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED,
+                    AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+            assertTrue(Environment.isExternalStorageManager());
+        } finally {
+            setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT,
+                    AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index 0a094c61d..f81964c 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -35,10 +35,13 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.graphics.Rect;
 import android.text.Layout;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
+import android.view.View;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.filters.SmallTest;
@@ -50,11 +53,13 @@
 
 import com.google.common.base.Strings;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 @RunWith(AndroidJUnit4.class)
@@ -70,6 +75,7 @@
 
     private Instrumentation mInstrumentation;
     private Activity mActivity;
+    private Set<MotionEvent> mMotionEvents = new ArraySet<>();
 
     @Before
     public void before() throws Throwable {
@@ -77,6 +83,14 @@
         mActivity = mActivityRule.getActivity();
     }
 
+    @After
+    public void after() throws Throwable {
+        for (MotionEvent event : mMotionEvents) {
+            event.recycle();
+        }
+        mMotionEvents.clear();
+    }
+
     @Test
     public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable {
         String text = "Hello world!";
@@ -243,45 +257,45 @@
 
         // Simulate a tap-and-drag gesture.
         long event1Time = 1001;
-        MotionEvent event1 = downEvent(event1Time, event1Time, 5f, 10f);
+        MotionEvent event1 = downEvent(tv, event1Time, event1Time, 5f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event2Time = 1002;
-        MotionEvent event2 = moveEvent(event1Time, event2Time, 50f, 10f);
+        MotionEvent event2 = moveEvent(tv, event1Time, event2Time, 50f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
         assertTrue(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event3Time = 1003;
-        MotionEvent event3 = moveEvent(event1Time, event3Time, 100f, 10f);
+        MotionEvent event3 = moveEvent(tv, event1Time, event3Time, 100f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
         assertTrue(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event4Time = 2004;
-        MotionEvent event4 = upEvent(event1Time, event4Time, 100f, 10f);
+        MotionEvent event4 = upEvent(tv, event1Time, event4Time, 100f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         // Simulate a quick tap after the drag, near the location where the drag ended.
         long event5Time = 2005;
-        MotionEvent event5 = downEvent(event5Time, event5Time, 90f, 10f);
+        MotionEvent event5 = downEvent(tv, event5Time, event5Time, 90f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event6Time = 2006;
-        MotionEvent event6 = upEvent(event5Time, event6Time, 90f, 10f);
+        MotionEvent event6 = upEvent(tv, event5Time, event6Time, 90f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event6));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         // Simulate another quick tap in the same location; now selection should be triggered.
         long event7Time = 2007;
-        MotionEvent event7 = downEvent(event7Time, event7Time, 90f, 10f);
+        MotionEvent event7 = downEvent(tv, event7Time, event7Time, 90f, 10f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event7));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertTrue(editor.getSelectionController().isCursorBeingModified());
@@ -298,19 +312,19 @@
 
         // Simulate a mouse click and drag. This should NOT trigger a cursor drag.
         long event1Time = 1001;
-        MotionEvent event1 = mouseDownEvent(event1Time, event1Time, 20f, 30f);
+        MotionEvent event1 = mouseDownEvent(tv, event1Time, event1Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event2Time = 1002;
-        MotionEvent event2 = mouseMoveEvent(event1Time, event2Time, 120f, 30f);
+        MotionEvent event2 = mouseMoveEvent(tv, event1Time, event2Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertTrue(editor.getSelectionController().isCursorBeingModified());
 
         long event3Time = 1003;
-        MotionEvent event3 = mouseUpEvent(event1Time, event3Time, 120f, 30f);
+        MotionEvent event3 = mouseUpEvent(tv, event1Time, event3Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -327,25 +341,25 @@
 
         // Simulate a tap-and-drag gesture. This should trigger a cursor drag.
         long event1Time = 1001;
-        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event2Time = 1002;
-        MotionEvent event2 = moveEvent(event1Time, event2Time, 21f, 30f);
+        MotionEvent event2 = moveEvent(tv, event1Time, event2Time, 21f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event3Time = 1003;
-        MotionEvent event3 = moveEvent(event1Time, event3Time, 120f, 30f);
+        MotionEvent event3 = moveEvent(tv, event1Time, event3Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
         assertTrue(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event4Time = 1004;
-        MotionEvent event4 = upEvent(event1Time, event4Time, 120f, 30f);
+        MotionEvent event4 = upEvent(tv, event1Time, event4Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -362,31 +376,31 @@
 
         // Simulate a double-tap followed by a drag. This should trigger a selection drag.
         long event1Time = 1001;
-        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event2Time = 1002;
-        MotionEvent event2 = upEvent(event1Time, event2Time, 20f, 30f);
+        MotionEvent event2 = upEvent(tv, event1Time, event2Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event2));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
 
         long event3Time = 1003;
-        MotionEvent event3 = downEvent(event3Time, event3Time, 20f, 30f);
+        MotionEvent event3 = downEvent(tv, event3Time, event3Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event3));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertTrue(editor.getSelectionController().isCursorBeingModified());
 
         long event4Time = 1004;
-        MotionEvent event4 = moveEvent(event3Time, event4Time, 120f, 30f);
+        MotionEvent event4 = moveEvent(tv, event3Time, event4Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event4));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertTrue(editor.getSelectionController().isCursorBeingModified());
 
         long event5Time = 1005;
-        MotionEvent event5 = upEvent(event3Time, event5Time, 120f, 30f);
+        MotionEvent event5 = upEvent(tv, event3Time, event5Time, 120f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event5));
         assertFalse(editor.getInsertionController().isCursorBeingModified());
         assertFalse(editor.getSelectionController().isCursorBeingModified());
@@ -403,7 +417,7 @@
 
         // Simulate a tap. No error should be thrown.
         long event1Time = 1001;
-        MotionEvent event1 = downEvent(event1Time, event1Time, 20f, 30f);
+        MotionEvent event1 = downEvent(tv, event1Time, event1Time, 20f, 30f);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event1));
 
         // Swipe left to right. No error should be thrown.
@@ -440,7 +454,8 @@
     public void testCursorDrag_snapToHandle() throws Throwable {
         String text = "line1: This is the 1st line: A\n"
                     + "line2: This is the 2nd line: B\n"
-                    + "line3: This is the 3rd line: C\n";
+                    + "line3: This is the 3rd line: C\n"
+                    + "line4: This is the 4th line: D\n";
         onView(withId(R.id.textview)).perform(replaceText(text));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0));
         TextView tv = mActivity.findViewById(R.id.textview);
@@ -454,8 +469,8 @@
                 // Start dragging along the first line
                 motionEventInfo(text.indexOf("line1"), 1.0f),
                 motionEventInfo(text.indexOf("This is the 1st"), 1.0f),
-                // Move to the bottom of the third line; cursor should end up on second line
-                motionEventInfo(text.indexOf("he 3rd"), 0.0f, text.indexOf("he 2nd")),
+                // Move to the middle of the fourth line; cursor should end up on second line
+                motionEventInfo(text.indexOf("he 4th"), 0.5f, text.indexOf("he 2nd")),
                 // Move to the middle of the second line; cursor should end up on the first line
                 motionEventInfo(text.indexOf("he 2nd"), 0.5f, text.indexOf("he 1st"))
         };
@@ -473,37 +488,137 @@
         simulateDrag(tv, events, true);
     }
 
-    private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
-        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+    @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"
+                + "line3: This is the 3rd line: C\n";
+        onView(withId(R.id.textview)).perform(replaceText(text));
+        TextView tv = mActivity.findViewById(R.id.textview);
+        Editor editor = tv.getEditorForTesting();
+        final int startIndex = text.indexOf("he 2nd");
+        Layout layout = tv.getLayout();
+        final float cursorStartX = layout.getPrimaryHorizontal(startIndex) + tv.getTotalPaddingLeft();
+        final float cursorStartY = layout.getLineTop(1) + tv.getTotalPaddingTop();
+        final float dragHandleStartX = 20;
+        final float dragHandleStartY = 20;
+
+        // Drag the handle from the 2nd line to the 3rd line.
+        tapAtPoint(tv, cursorStartX, cursorStartY);
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+        View handleView = editor.getInsertionController().getHandle();
+        final int rawYOfHandleDrag = dragDownUntilLineChange(
+                handleView, dragHandleStartX, dragHandleStartY, tv.getSelectionStart());
+
+        // Drag the cursor from the 2nd line to the 3rd line.
+        tapAtPoint(tv, cursorStartX, cursorStartY);
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+        final int rawYOfCursorDrag =
+                dragDownUntilLineChange(tv, cursorStartX, cursorStartY, tv.getSelectionStart());
+
+        // Drag the handle with touch through from the 2nd line to the 3rd line.
+        tv.getEditorForTesting().setFlagInsertionHandleGesturesEnabled(true);
+        tapAtPoint(tv, cursorStartX, cursorStartY);
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(startIndex));
+        handleView = editor.getInsertionController().getHandle();
+        int rawYOfHandleDragWithTouchThrough =
+                dragDownUntilLineChange(handleView, dragHandleStartX, dragHandleStartY, tv.getSelectionStart());
+
+        String msg = String.format(
+                "rawYOfHandleDrag: %d, rawYOfCursorDrag: %d, rawYOfHandleDragWithTouchThrough: %d",
+                rawYOfHandleDrag, rawYOfCursorDrag, rawYOfHandleDragWithTouchThrough);
+        final int max = Math.max(
+                rawYOfCursorDrag, Math.max(rawYOfHandleDrag, rawYOfHandleDragWithTouchThrough));
+        final int min = Math.min(
+                rawYOfCursorDrag, Math.min(rawYOfHandleDrag, rawYOfHandleDragWithTouchThrough));
+        // The drag step is 5 pixels in dragDownUntilLineChange().
+        // The difference among the 3 raw Y values should be no bigger than the drag step.
+        assertWithMessage(msg).that(max - min).isLessThan(6);
     }
 
-    private static MotionEvent upEvent(long downTime, long eventTime, float x, float y) {
-        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+    private void dispatchTouchEvent(View view, MotionEvent event) {
+        mInstrumentation.runOnMainSync(() -> view.dispatchTouchEvent(event));
     }
 
-    private static MotionEvent moveEvent(long downTime, long eventTime, float x, float y) {
-        return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+    private void tapAtPoint(TextView tv, final float x, final float y) {
+        long downTime = sTicker.addAndGet(10_000);
+        dispatchTouchEvent(tv, downEvent(tv, downTime, downTime, x, y));
+        dispatchTouchEvent(tv, upEvent(tv, downTime, downTime + 1, x, y));
     }
 
-    private static MotionEvent mouseDownEvent(long downTime, long eventTime, float x, float y) {
-        MotionEvent event = downEvent(downTime, eventTime, x, y);
-        event.setSource(InputDevice.SOURCE_MOUSE);
-        event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+    private int dragDownUntilLineChange(View view, final float startX, final float startY,
+            final int startOffset) {
+        TextView tv = mActivity.findViewById(R.id.textview);
+        final int startLine = tv.getLayout().getLineForOffset(startOffset);
+
+        int rawY = 0;
+        long downTime = sTicker.addAndGet(10_000);
+        long eventTime = downTime;
+        // Move horizontally first to initiate the cursor drag.
+        dispatchTouchEvent(view, downEvent(view, downTime, eventTime++, startX, startY));
+        dispatchTouchEvent(view, moveEvent(view, downTime, eventTime++, startX + 50, startY));
+        dispatchTouchEvent(view, moveEvent(view, downTime, eventTime++, startX, startY));
+        // Move downwards 5 pixels at a time until a line change occurs.
+        for (int i = 0; i < 200; i++) {
+            MotionEvent ev = moveEvent(view, downTime, eventTime++, startX, startY + i * 5);
+            rawY = (int) ev.getRawY();
+            dispatchTouchEvent(view, ev);
+            if (tv.getLayout().getLineForOffset(tv.getSelectionStart()) > startLine) {
+                break;
+            }
+        }
+        String msg = String.format("The cursor didn't jump from %d!", startOffset);
+        assertWithMessage(msg).that(
+                tv.getLayout().getLineForOffset(tv.getSelectionStart())).isGreaterThan(startLine);
+        dispatchTouchEvent(view, upEvent(view, downTime, eventTime, startX, startY));
+        return rawY;
+    }
+
+    private MotionEvent obtainTouchEvent(
+            View view, int action, long downTime, long eventTime, float x, float y) {
+        Rect r = new Rect();
+        view.getBoundsOnScreen(r);
+        float rawX = x + r.left;
+        float rawY = y + r.top;
+        MotionEvent event =
+                MotionEvent.obtain(downTime, eventTime, action, rawX, rawY, 0);
+        view.toLocalMotionEvent(event);
+        mMotionEvents.add(event);
         return event;
     }
 
-    private static MotionEvent mouseUpEvent(long downTime, long eventTime, float x, float y) {
-        MotionEvent event = upEvent(downTime, eventTime, x, y);
+    private MotionEvent obtainMouseEvent(
+            View view, int action, long downTime, long eventTime, float x, float y) {
+        MotionEvent event = obtainTouchEvent(view, action, downTime, eventTime, x, y);
         event.setSource(InputDevice.SOURCE_MOUSE);
-        event.setButtonState(0);
+        if (action != MotionEvent.ACTION_UP) {
+            event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+        }
         return event;
     }
 
-    private static MotionEvent mouseMoveEvent(long downTime, long eventTime, float x, float y) {
-        MotionEvent event = moveEvent(downTime, eventTime, x, y);
-        event.setSource(InputDevice.SOURCE_MOUSE);
-        event.setButtonState(MotionEvent.BUTTON_PRIMARY);
-        return event;
+    private MotionEvent downEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainTouchEvent(view, MotionEvent.ACTION_DOWN, downTime, eventTime, x, y);
+    }
+
+    private MotionEvent moveEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainTouchEvent(view, MotionEvent.ACTION_MOVE, downTime, eventTime, x, y);
+    }
+
+    private MotionEvent upEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainTouchEvent(view, MotionEvent.ACTION_UP, downTime, eventTime, x, y);
+    }
+
+    private MotionEvent mouseDownEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainMouseEvent(view, MotionEvent.ACTION_DOWN, downTime, eventTime, x, y);
+    }
+
+    private MotionEvent mouseMoveEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainMouseEvent(view, MotionEvent.ACTION_MOVE, downTime, eventTime, x, y);
+    }
+
+    private MotionEvent mouseUpEvent(View view, long downTime, long eventTime, float x, float y) {
+        return obtainMouseEvent(view, MotionEvent.ACTION_UP, downTime, eventTime, x, y);
     }
 
     public static MotionEventInfo motionEventInfo(int index, float ratioToLineTop) {
@@ -543,14 +658,15 @@
 
         float[] downCoords = events[0].getCoordinates(tv);
         long downEventTime = sTicker.addAndGet(10_000);
-        MotionEvent downEvent = downEvent(downEventTime, downEventTime,
+        MotionEvent downEvent = downEvent(tv,  downEventTime, downEventTime,
                 downCoords[0], downCoords[1]);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(downEvent));
 
         for (int i = 1; i < events.length; i++) {
             float[] moveCoords = events[i].getCoordinates(tv);
             long eventTime = downEventTime + i;
-            MotionEvent event = moveEvent(downEventTime, eventTime, moveCoords[0], moveCoords[1]);
+            MotionEvent event = moveEvent(tv, downEventTime, eventTime, moveCoords[0],
+                    moveCoords[1]);
             mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(event));
             assertCursorPosition(tv, events[i].expectedCursorIndex, runAssertions);
         }
@@ -558,7 +674,7 @@
         MotionEventInfo lastEvent = events[events.length - 1];
         float[] upCoords = lastEvent.getCoordinates(tv);
         long upEventTime = downEventTime + events.length;
-        MotionEvent upEvent = upEvent(downEventTime, upEventTime, upCoords[0], upCoords[1]);
+        MotionEvent upEvent = upEvent(tv, downEventTime, upEventTime, upCoords[0], upCoords[1]);
         mInstrumentation.runOnMainSync(() -> editor.onTouchEvent(upEvent));
     }
 
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 88a6f9e..a72be25 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -497,7 +497,7 @@
 
     @Test
     public void testInsertionHandle_multiLine() {
-        final String text = "abcd\n" + "efg\n" + "hijk\n";
+        final String text = "abcd\n" + "efg\n" + "hijk\n" + "lmn\n";
         onView(withId(R.id.textview)).perform(replaceText(text));
 
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(text.length()));
@@ -506,12 +506,12 @@
         final TextView textView = mActivity.findViewById(R.id.textview);
 
         onHandleView(com.android.internal.R.id.insertion_handle)
-                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('a')));
-        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("a")));
-
-        onHandleView(com.android.internal.R.id.insertion_handle)
                 .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('f')));
         onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("f")));
+
+        onHandleView(com.android.internal.R.id.insertion_handle)
+                .perform(dragHandle(textView, Handle.INSERTION, text.indexOf('i')));
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(text.indexOf("i")));
     }
 
     private void enableFlagsForInsertionHandleGestures() {
diff --git a/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index b6671db..1e570ba 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -20,6 +20,7 @@
         <permission name="android.permission.INTERACT_ACROSS_USERS"/>
         <!-- Permissions required for reading and logging compat changes -->
         <permission name="android.permission.LOG_COMPAT_CHANGE"/>
+        <permission name="android.permission.MODIFY_QUIET_MODE"/>
         <permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 38e18a9..72827a9 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -63,5 +63,6 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
         <permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
         <permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+        <permission name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
     </privapp-permissions>
 </permissions>
diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java
index ef7afca..2ef735e 100644
--- a/identity/java/android/security/identity/CredstoreResultData.java
+++ b/identity/java/android/security/identity/CredstoreResultData.java
@@ -66,7 +66,7 @@
     }
 
     @Override
-    public @NonNull Collection<String> getNamespaceNames() {
+    public @NonNull Collection<String> getNamespaces() {
         return Collections.unmodifiableCollection(mData.keySet());
     }
 
diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
index 335636c..725e3d8 100644
--- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java
@@ -105,11 +105,11 @@
             n++;
         }
 
-        Collection<String> namespaceNames = personalizationData.getNamespaceNames();
+        Collection<String> namespaces = personalizationData.getNamespaces();
 
-        EntryNamespaceParcel[] ensParcels  = new EntryNamespaceParcel[namespaceNames.size()];
+        EntryNamespaceParcel[] ensParcels  = new EntryNamespaceParcel[namespaces.size()];
         n = 0;
-        for (String namespaceName : namespaceNames) {
+        for (String namespaceName : namespaces) {
             PersonalizationData.NamespaceData nsd =
                     personalizationData.getNamespaceData(namespaceName);
 
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index bd43919..1db2f63 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -209,6 +209,11 @@
      * <p>Note that only items referenced in {@code entriesToRequest} are returned - the
      * {@code requestMessage} parameter is only used to for enforcing reader authentication.
      *
+     * <p>The reason for having {@code requestMessage} and {@code entriesToRequest} as separate
+     * parameters is that the former represents a request from the remote verifier device
+     * (optionally signed) and this allows the application to filter the request to not include
+     * data elements which the user has not consented to sharing.
+     *
      * @param requestMessage         If not {@code null}, must contain CBOR data conforming to
      *                               the schema mentioned above.
      * @param entriesToRequest       The entries to request, organized as a map of namespace
diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java
index 44370a1..b34f250 100644
--- a/identity/java/android/security/identity/PersonalizationData.java
+++ b/identity/java/android/security/identity/PersonalizationData.java
@@ -46,7 +46,7 @@
         return Collections.unmodifiableCollection(mProfiles);
     }
 
-    Collection<String> getNamespaceNames() {
+    Collection<String> getNamespaces() {
         return Collections.unmodifiableCollection(mNamespaces.keySet());
     }
 
@@ -120,7 +120,7 @@
          * @param value                   The value to add, in CBOR encoding.
          * @return The builder.
          */
-        public @NonNull Builder setEntry(@NonNull String namespace, @NonNull String name,
+        public @NonNull Builder putEntry(@NonNull String namespace, @NonNull String name,
                 @NonNull Collection<AccessControlProfileId> accessControlProfileIds,
                 @NonNull byte[] value) {
             NamespaceData namespaceData = mData.mNamespaces.get(namespace);
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
index 0982c8a..13552d6 100644
--- a/identity/java/android/security/identity/ResultData.java
+++ b/identity/java/android/security/identity/ResultData.java
@@ -152,7 +152,7 @@
      * @return collection of name of namespaces containing retrieved entries. May be empty if no
      *     data was retrieved.
      */
-    public abstract @NonNull Collection<String> getNamespaceNames();
+    public abstract @NonNull Collection<String> getNamespaces();
 
     /**
      * Get the names of all entries.
@@ -196,8 +196,7 @@
      * @param name the name of the entry to get the value for.
      * @return the status indicating whether the value was retrieved and if not, why.
      */
-    @Status
-    public abstract int getStatus(@NonNull String namespaceName, @NonNull String name);
+    public abstract @Status int getStatus(@NonNull String namespaceName, @NonNull String name);
 
     /**
      * Gets the raw CBOR data for the value of an entry.
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 84c07d7..39900e6 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -146,12 +146,11 @@
     }
 
     Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
-    bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
-                         MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
-    layer.setForceFilter(!disableFilter);
     layer.setSize(displayedWidth, displayedHeight);
     texTransform.copyTo(layer.getTexTransform());
     layer.setImage(image);
+    // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
+    // after checking the necessity based on the src/dest rect size and the transformation.
     if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
         copyResult = CopyResult::Success;
     }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index e230917..550e41f 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -103,6 +103,16 @@
     private final Object mLock = new Object();
 
     /**
+     * For apps targeting Android R and above, {@link #getProvider(String)} will no longer throw any
+     * security exceptions.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+    private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
+
+    /**
      * For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
      * specific package.
      *
@@ -1401,6 +1411,22 @@
      */
     public @Nullable LocationProvider getProvider(@NonNull String provider) {
         Preconditions.checkArgument(provider != null, "invalid null provider");
+
+        if (!Compatibility.isChangeEnabled(GET_PROVIDER_SECURITY_EXCEPTIONS)) {
+            if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
+                try {
+                    mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(),
+                            Process.myUid(), null);
+                } catch (SecurityException e) {
+                    mContext.enforcePermission(ACCESS_COARSE_LOCATION, Process.myPid(),
+                            Process.myUid(), null);
+                }
+            } else {
+                mContext.enforcePermission(ACCESS_FINE_LOCATION, Process.myPid(), Process.myUid(),
+                        null);
+            }
+        }
+
         try {
             ProviderProperties properties = mService.getProviderProperties(provider);
             if (properties == null) {
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 45b849f..37e2ab5 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -377,7 +377,9 @@
      * @see TransferCallback#onTransferred
      * @see TransferCallback#onTransferFailed
      */
-    public void transferTo(@Nullable MediaRoute2Info route) {
+    public void transferTo(@NonNull MediaRoute2Info route) {
+        Objects.requireNonNull(route, "route must not be null");
+
         List<RoutingController> controllers = getControllers();
         RoutingController controller = controllers.get(controllers.size() - 1);
 
@@ -385,19 +387,25 @@
     }
 
     /**
+     * Stops the current media routing. If the {@link #getSystemController() system controller}
+     * controls the media routing, this method is a no-op.
+     */
+    public void stop() {
+        List<RoutingController> controllers = getControllers();
+        RoutingController controller = controllers.get(controllers.size() - 1);
+
+        controller.release();
+    }
+
+    /**
      * Transfers the media of a routing controller to the given route.
      * @param controller a routing controller controlling media routing.
-     * @param route the route you want to transfer the media to. Pass {@code null} to stop
-     *              routing controlled by the given controller.
+     * @param route the route you want to transfer the media to.
      * @hide
      */
-    void transfer(@NonNull RoutingController controller, @Nullable MediaRoute2Info route) {
+    void transfer(@NonNull RoutingController controller, @NonNull MediaRoute2Info route) {
         Objects.requireNonNull(controller, "controller must not be null");
-
-        if (route == null) {
-            controller.release();
-            return;
-        }
+        Objects.requireNonNull(route, "route must not be null");
 
         // TODO: Check thread-safety
         if (!mRoutes.containsKey(route.getId())) {
@@ -681,7 +689,7 @@
 
         if (removed) {
             matchingController.release();
-            notifyControllerReleased(matchingController);
+            notifyStopped(matchingController);
         }
     }
 
@@ -738,16 +746,16 @@
         }
     }
 
-    private void notifyControllerUpdated(RoutingController controller) {
-        for (ControllerCallbackRecord record: mControllerCallbackRecords) {
-            record.mExecutor.execute(() -> record.mCallback.onControllerUpdated(controller));
+    private void notifyStopped(RoutingController controller) {
+        for (TransferCallbackRecord record: mTransferCallbackRecords) {
+            record.mExecutor.execute(
+                    () -> record.mTransferCallback.onStopped(controller));
         }
     }
 
-    private void notifyControllerReleased(RoutingController controller) {
-        for (TransferCallbackRecord record: mTransferCallbackRecords) {
-            record.mExecutor.execute(
-                    () -> record.mTransferCallback.onTransferred(controller, null));
+    private void notifyControllerUpdated(RoutingController controller) {
+        for (ControllerCallbackRecord record: mControllerCallbackRecords) {
+            record.mExecutor.execute(() -> record.mCallback.onControllerUpdated(controller));
         }
     }
 
@@ -788,20 +796,26 @@
          * This can happen by calling {@link #transferTo(MediaRoute2Info)} or
          * {@link RoutingController#release()}.
          *
-         * @param oldController the previous controller that controlled routing.
-         * @param newController the new controller to control routing or {@code null} if the
-         *                      previous controller is released.
+         * @param oldController the previous controller that controlled routing
+         * @param newController the new controller to control routing
          * @see #transferTo(MediaRoute2Info)
          */
         public void onTransferred(@NonNull RoutingController oldController,
-                @Nullable RoutingController newController) {}
+                @NonNull RoutingController newController) {}
 
         /**
          * Called when {@link #transferTo(MediaRoute2Info)} failed.
          *
-         * @param requestedRoute the route info which was used for the transfer.
+         * @param requestedRoute the route info which was used for the transfer
          */
         public void onTransferFailed(@NonNull MediaRoute2Info requestedRoute) {}
+
+        /**
+         * Called when a media routing stops. It can be stopped by a user or a provider.
+         *
+         * @param controller the controller that controlled the stopped media routing.
+         */
+        public void onStopped(@NonNull RoutingController controller) { }
     }
 
     /**
@@ -1186,7 +1200,7 @@
             }
 
             if (removed) {
-                mHandler.post(() -> notifyControllerReleased(RoutingController.this));
+                mHandler.post(() -> notifyStopped(RoutingController.this));
             }
 
             if (stub != null) {
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 7932dcb..ea06632 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -156,7 +156,7 @@
 
     private long mNativeContext;
 
-    Lnb(int id) {
+    private Lnb(int id) {
         mId = id;
     }
 
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index bcbc12b..08a33f1 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -43,7 +43,11 @@
 import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType;
 import android.media.tv.tuner.frontend.OnTuneEventListener;
 import android.media.tv.tuner.frontend.ScanCallback;
+import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerLnbRequest;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.Looper;
 import android.os.Message;
 
@@ -67,6 +71,7 @@
     private static final String TAG = "MediaTvTuner";
     private static final boolean DEBUG = false;
 
+    private static final int MSG_RESOURCE_LOST = 1;
     private static final int MSG_ON_FILTER_EVENT = 2;
     private static final int MSG_ON_FILTER_STATUS = 3;
     private static final int MSG_ON_LNB_EVENT = 4;
@@ -93,6 +98,8 @@
     }
 
     private final Context mContext;
+    private final TunerResourceManager mTunerResourceManager;
+    private final int mClientId;
 
     private List<Integer> mFrontendIds;
     private Frontend mFrontend;
@@ -102,6 +109,7 @@
 
     private List<Integer> mLnbIds;
     private Lnb mLnb;
+    private Integer mLnbId;
     @Nullable
     private OnTuneEventListener mOnTuneEventListener;
     @Nullable
@@ -115,6 +123,15 @@
     @Nullable
     private Executor mOnResourceLostListenerExecutor;
 
+
+    private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
+            new TunerResourceManager.ResourcesReclaimListener() {
+                @Override
+                public void onReclaimResources() {
+                    mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
+                }
+            };
+
     /**
      * Constructs a Tuner instance.
      *
@@ -127,6 +144,14 @@
             @TvInputService.PriorityHintUseCaseType int useCase) {
         nativeSetup();
         mContext = context;
+        mTunerResourceManager = (TunerResourceManager)
+                context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+
+        int[] clientId = new int[1];
+        ResourceClientProfile profile = new ResourceClientProfile(tvInputSessionId, useCase);
+        mTunerResourceManager.registerClientProfile(
+                profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
+        mClientId = clientId[0];
     }
 
     /**
@@ -226,6 +251,7 @@
 
     private native List<Integer> nativeGetLnbIds();
     private native Lnb nativeOpenLnbById(int id);
+    private native Lnb nativeOpenLnbByName(String name);
 
     private native Descrambler nativeOpenDescrambler();
 
@@ -275,6 +301,14 @@
                     }
                     break;
                 }
+                case MSG_RESOURCE_LOST: {
+                    if (mOnResourceLostListener != null
+                                && mOnResourceLostListenerExecutor != null) {
+                        mOnResourceLostListenerExecutor.execute(
+                                () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+                    }
+                    break;
+                }
                 default:
                     // fall through
             }
@@ -698,7 +732,10 @@
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(cb, "LnbCallback must not be null");
         TunerUtils.checkTunerPermission(mContext);
-        return openLnbByName(null, executor, cb);
+        if (mLnbId == null && !requestLnb()) {
+            return null;
+        }
+        return nativeOpenLnbById(mLnbId);
     }
 
     /**
@@ -714,11 +751,21 @@
     @Nullable
     public Lnb openLnbByName(@NonNull String name, @CallbackExecutor @NonNull Executor executor,
             @NonNull LnbCallback cb) {
+        Objects.requireNonNull(name, "LNB name must not be null");
         Objects.requireNonNull(executor, "executor must not be null");
         Objects.requireNonNull(cb, "LnbCallback must not be null");
         TunerUtils.checkTunerPermission(mContext);
-        // TODO: use resource manager to get LNB ID.
-        return new Lnb(0);
+        return nativeOpenLnbByName(name);
+    }
+
+    private boolean requestLnb() {
+        int[] lnbId = new int[1];
+        TunerLnbRequest request = new TunerLnbRequest(mClientId);
+        boolean granted = mTunerResourceManager.requestLnb(request, lnbId);
+        if (granted) {
+            mLnbId = lnbId[0];
+        }
+        return granted;
     }
 
     /**
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 7b29494..8a29442 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
@@ -33,7 +34,7 @@
  * @hide
  */
 @SystemApi
-public class AlpFilterConfiguration extends FilterConfiguration {
+public final class AlpFilterConfiguration extends FilterConfiguration {
     /**
      * IPv4 packet type.
      */
@@ -123,9 +124,10 @@
     /**
      * Builder for {@link AlpFilterConfiguration}.
      */
-    public static class Builder extends FilterConfiguration.Builder<Builder> {
+    public static final class Builder {
         private int mPacketType;
         private int mLengthType;
+        private Settings mSettings;
 
         private Builder() {
         }
@@ -150,16 +152,20 @@
         }
 
         /**
+         * Sets filter settings.
+         */
+        @NonNull
+        public Builder setSettings(@Nullable Settings settings) {
+            mSettings = settings;
+            return this;
+        }
+
+        /**
          * Builds a {@link AlpFilterConfiguration} object.
          */
         @NonNull
         public AlpFilterConfiguration build() {
             return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType);
         }
-
-        @Override
-        Builder self() {
-            return this;
-        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 52bdb59..4777fe8 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -225,6 +225,7 @@
         mCallback = cb;
         mExecutor = executor;
     }
+
     /** @hide */
     public FilterCallback getCallback() {
         return mCallback;
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index a8c9356..dd7e5fc 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,7 +16,6 @@
 
 package android.media.tv.tuner.filter;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 
@@ -48,26 +47,4 @@
     public Settings getSettings() {
         return mSettings;
     }
-
-    /**
-     * Builder for {@link FilterConfiguration}.
-     *
-     * @param <T> The subclass to be built.
-     */
-    public abstract static class Builder<T extends Builder<T>> {
-        /* package */ Settings mSettings;
-
-        /* package */ Builder() {
-        }
-
-        /**
-         * Sets filter settings.
-         */
-        @NonNull
-        public T setSettings(@Nullable Settings settings) {
-            mSettings = settings;
-            return self();
-        }
-        /* package */ abstract T self();
-    }
 }
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index a8dbfa5..04f3410 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -17,6 +17,7 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
 import android.annotation.SystemApi;
@@ -29,7 +30,7 @@
  * @hide
  */
 @SystemApi
-public class IpFilterConfiguration extends FilterConfiguration {
+public final class IpFilterConfiguration extends FilterConfiguration {
     private final byte[] mSrcIpAddress;
     private final byte[] mDstIpAddress;
     private final int mSrcPort;
@@ -104,12 +105,13 @@
     /**
      * Builder for {@link IpFilterConfiguration}.
      */
-    public static class Builder extends FilterConfiguration.Builder<Builder> {
+    public static final class Builder {
         private byte[] mSrcIpAddress;
         private byte[] mDstIpAddress;
         private int mSrcPort;
         private int mDstPort;
         private boolean mPassthrough;
+        private Settings mSettings;
 
         private Builder() {
         }
@@ -156,6 +158,15 @@
         }
 
         /**
+         * Sets filter settings.
+         */
+        @NonNull
+        public Builder setSettings(@Nullable Settings settings) {
+            mSettings = settings;
+            return this;
+        }
+
+        /**
          * Builds a {@link IpFilterConfiguration} object.
          */
         @NonNull
@@ -169,10 +180,5 @@
             return new IpFilterConfiguration(
                     mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
         }
-
-        @Override
-        Builder self() {
-            return this;
-        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 0601829..c0453b4 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -17,6 +17,7 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
@@ -28,7 +29,7 @@
  * @hide
  */
 @SystemApi
-public class MmtpFilterConfiguration extends FilterConfiguration {
+public final class MmtpFilterConfiguration extends FilterConfiguration {
     private final int mMmtpPid;
 
     private MmtpFilterConfiguration(Settings settings, int mmtpPid) {
@@ -65,8 +66,9 @@
     /**
      * Builder for {@link IpFilterConfiguration}.
      */
-    public static class Builder extends FilterConfiguration.Builder<Builder> {
+    public static final class Builder {
         private int mMmtpPid;
+        private Settings mSettings;
 
         private Builder() {
         }
@@ -81,16 +83,20 @@
         }
 
         /**
+         * Sets filter settings.
+         */
+        @NonNull
+        public Builder setSettings(@Nullable Settings settings) {
+            mSettings = settings;
+            return this;
+        }
+
+        /**
          * Builds a {@link IpFilterConfiguration} object.
          */
         @NonNull
         public MmtpFilterConfiguration build() {
             return new MmtpFilterConfiguration(mSettings, mMmtpPid);
         }
-
-        @Override
-        Builder self() {
-            return this;
-        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index ac4fc83..c5191bf 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -17,6 +17,7 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
@@ -28,7 +29,7 @@
  * @hide
  */
 @SystemApi
-public class TlvFilterConfiguration extends FilterConfiguration {
+public final class TlvFilterConfiguration extends FilterConfiguration {
     /**
      * IPv4 packet type.
      */
@@ -108,10 +109,11 @@
     /**
      * Builder for {@link TlvFilterConfiguration}.
      */
-    public static class Builder extends FilterConfiguration.Builder<Builder> {
+    public static final class Builder {
         private int mPacketType;
         private boolean mIsCompressedIpPacket;
         private boolean mPassthrough;
+        private Settings mSettings;
 
         private Builder() {
         }
@@ -144,6 +146,15 @@
         }
 
         /**
+         * Sets filter settings.
+         */
+        @NonNull
+        public Builder setSettings(@Nullable Settings settings) {
+            mSettings = settings;
+            return this;
+        }
+
+        /**
          * Builds a {@link TlvFilterConfiguration} object.
          */
         @NonNull
@@ -151,10 +162,5 @@
             return new TlvFilterConfiguration(
                     mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough);
         }
-
-        @Override
-        Builder self() {
-            return this;
-        }
     }
 }
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
index 6a8b6da..a7140eb 100644
--- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -17,6 +17,7 @@
 package android.media.tv.tuner.filter;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
@@ -28,7 +29,7 @@
  * @hide
  */
 @SystemApi
-public class TsFilterConfiguration extends FilterConfiguration {
+public final class TsFilterConfiguration extends FilterConfiguration {
     private final int mTpid;
 
     private TsFilterConfiguration(Settings settings, int tpid) {
@@ -63,8 +64,9 @@
     /**
      * Builder for {@link TsFilterConfiguration}.
      */
-    public static class Builder extends FilterConfiguration.Builder<Builder> {
+    public static final class Builder {
         private int mTpid;
+        private Settings mSettings;
 
         private Builder() {
         }
@@ -81,16 +83,20 @@
         }
 
         /**
+         * Sets filter settings.
+         */
+        @NonNull
+        public Builder setSettings(@Nullable Settings settings) {
+            mSettings = settings;
+            return this;
+        }
+
+        /**
          * Builds a {@link TsFilterConfiguration} object.
          */
         @NonNull
         public TsFilterConfiguration build() {
             return new TsFilterConfiguration(mSettings, mTpid);
         }
-
-        @Override
-        Builder self() {
-            return this;
-        }
     }
 }
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 737c95d..893e516 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -242,13 +242,6 @@
     });
 }
 
-void JMediaCodec::releaseAsync() {
-    if (mCodec != NULL) {
-        mCodec->releaseAsync();
-    }
-    mInitStatus = NO_INIT;
-}
-
 JMediaCodec::~JMediaCodec() {
     if (mLooper != NULL) {
         /* MediaCodec and looper should have been released explicitly already
@@ -1131,10 +1124,7 @@
 }
 
 static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
-    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
-    if (codec != NULL) {
-        codec->releaseAsync();
-    }
+    setMediaCodec(env, thiz, NULL);
 }
 
 static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
@@ -2807,7 +2797,7 @@
 
 static void android_media_MediaCodec_native_finalize(
         JNIEnv *env, jobject thiz) {
-    setMediaCodec(env, thiz, NULL);
+    android_media_MediaCodec_release(env, thiz);
 }
 
 // MediaCodec.LinearBlock
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1b..8899fee 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -61,7 +61,6 @@
 
     void registerSelf();
     void release();
-    void releaseAsync();
 
     status_t enableOnFrameRenderedListener(jboolean enable);
 
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 273c776..679f18a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -34,19 +34,28 @@
 using ::android::hardware::Void;
 using ::android::hardware::hidl_bitfield;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData;
+using ::android::hardware::tv::tuner::V1_0::Constant;
 using ::android::hardware::tv::tuner::V1_0::DataFormat;
 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::DemuxFilterAvSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
 using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
 using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
@@ -136,6 +145,7 @@
     jmethodID dvrInitID;
     jmethodID onFrontendEventID;
     jmethodID onFilterStatusID;
+    jmethodID onFilterEventID;
     jmethodID lnbInitID;
     jmethodID onLnbEventID;
     jmethodID descramblerInitID;
@@ -248,48 +258,287 @@
     return linearBlock;
 }
 
-jobject FilterCallback::getMediaEvent(const DemuxFilterEvent::Event& event) {
+jobjectArray FilterCallback::getSectionEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jclass clazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
-    jmethodID eventInit = env->GetMethodID(clazz,
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIII)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterSectionEvent sectionEvent = event.section();
+
+        jint tableId = static_cast<jint>(sectionEvent.tableId);
+        jint version = static_cast<jint>(sectionEvent.version);
+        jint sectionNum = static_cast<jint>(sectionEvent.sectionNum);
+        jint dataLength = static_cast<jint>(sectionEvent.dataLength);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getMediaEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz,
             "<init>",
             "(IZJJJLandroid/media/MediaCodec$LinearBlock;"
             "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
 
-    DemuxFilterMediaEvent mediaEvent = event.media();
-    uint32_t dataLength = mediaEvent.dataLength;
-    const native_handle_t* h = mediaEvent.avMemory.getNativeHandle();
-    jobject block = handleToLinearBlock(h, dataLength);
-    // TODO: handle other fields
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterMediaEvent mediaEvent = event.media();
 
-    return env->NewObject(clazz, eventInit, (jint) 0, (jboolean) 0, (jlong) 0, (jlong) 0, (jlong) 0,
-            block, (jboolean) 0, (jlong) 0, (jint) 0, (jboolean) 0, NULL);
+        jobject audioDescriptor = NULL;
+        if (mediaEvent.extraMetaData.getDiscriminator()
+                == DemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
+            jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor");
+            jmethodID adInit = env->GetMethodID(adClazz, "<init>", "(BBCBBB)V");
+
+            AudioExtraMetaData ad = mediaEvent.extraMetaData.audio();
+            jbyte adFade = static_cast<jbyte>(ad.adFade);
+            jbyte adPan = static_cast<jbyte>(ad.adPan);
+            jchar versionTextTag = static_cast<jchar>(ad.versionTextTag);
+            jbyte adGainCenter = static_cast<jbyte>(ad.adGainCenter);
+            jbyte adGainFront = static_cast<jbyte>(ad.adGainFront);
+            jbyte adGainSurround = static_cast<jbyte>(ad.adGainSurround);
+
+            audioDescriptor =
+                    env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, adGainCenter,
+                            adGainFront, adGainSurround);
+        }
+
+        jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
+        const native_handle_t* h = NULL;
+        jobject block = NULL;
+        if (mediaEvent.avMemory != NULL) {
+            h = mediaEvent.avMemory.getNativeHandle();
+            block = handleToLinearBlock(h, dataLength);
+        }
+
+        jint streamId = static_cast<jint>(mediaEvent.streamId);
+        jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
+        jlong pts = static_cast<jlong>(mediaEvent.pts);
+        jlong offset = static_cast<jlong>(mediaEvent.offset);
+        jboolean isSecureMemory = static_cast<jboolean>(mediaEvent.isSecureMemory);
+        jlong avDataId = static_cast<jlong>(mediaEvent.avDataId);
+        jint mpuSequenceNumber = static_cast<jint>(mediaEvent.mpuSequenceNumber);
+        jboolean isPesPrivateData = static_cast<jboolean>(mediaEvent.isPesPrivateData);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
+                offset, block, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
+                audioDescriptor);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getPesEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(III)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterPesEvent pesEvent = event.pes();
+
+        jint streamId = static_cast<jint>(pesEvent.streamId);
+        jint dataLength = static_cast<jint>(pesEvent.dataLength);
+        jint mpuSequenceNumber = static_cast<jint>(pesEvent.mpuSequenceNumber);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getTsRecordEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJ)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterTsRecordEvent tsRecordEvent = event.tsRecord();
+        DemuxPid pid = tsRecordEvent.pid;
+
+        jint jpid = static_cast<jint>(Constant::INVALID_TS_PID);
+
+        if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
+            jpid = static_cast<jint>(pid.tPid());
+        } else if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::mmtpPid) {
+            jpid = static_cast<jint>(pid.mmtpPid());
+        }
+
+        jint sc = 0;
+
+        if (tsRecordEvent.scIndexMask.getDiscriminator()
+                == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) {
+            sc = static_cast<jint>(tsRecordEvent.scIndexMask.sc());
+        } else if (tsRecordEvent.scIndexMask.getDiscriminator()
+                == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) {
+            sc = static_cast<jint>(tsRecordEvent.scIndexMask.scHevc());
+        }
+
+        jint ts = static_cast<jint>(tsRecordEvent.tsIndexMask);
+
+        jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getMmtpRecordEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJ)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord();
+
+        jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
+        jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getDownloadEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIII)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterDownloadEvent downloadEvent = event.download();
+
+        jint itemId = static_cast<jint>(downloadEvent.itemId);
+        jint mpuSequenceNumber = static_cast<jint>(downloadEvent.mpuSequenceNumber);
+        jint itemFragmentIndex = static_cast<jint>(downloadEvent.itemFragmentIndex);
+        jint lastItemFragmentIndex = static_cast<jint>(downloadEvent.lastItemFragmentIndex);
+        jint dataLength = static_cast<jint>(downloadEvent.dataLength);
+
+        jobject obj =
+                env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber, itemFragmentIndex,
+                        lastItemFragmentIndex, dataLength);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getIpPayloadEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterIpPayloadEvent ipPayloadEvent = event.ipPayload();
+        jint dataLength = static_cast<jint>(ipPayloadEvent.dataLength);
+        jobject obj = env->NewObject(eventClazz, eventInit, dataLength);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
+}
+
+jobjectArray FilterCallback::getTemiEvent(
+        jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
+    jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(JB[B)V");
+
+    for (int i = 0; i < events.size(); i++) {
+        auto event = events[i];
+        DemuxFilterTemiEvent temiEvent = event.temi();
+        jlong pts = static_cast<jlong>(temiEvent.pts);
+        jbyte descrTag = static_cast<jbyte>(temiEvent.descrTag);
+        std::vector<uint8_t> descrData = temiEvent.descrData;
+
+        jbyteArray array = env->NewByteArray(descrData.size());
+        env->SetByteArrayRegion(
+                array, 0, descrData.size(), reinterpret_cast<jbyte*>(&descrData[0]));
+
+        jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array);
+        env->SetObjectArrayElement(arr, i, obj);
+    }
+    return arr;
 }
 
 Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
     ALOGD("FilterCallback::onFilterEvent");
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    jclass clazz = env->FindClass("android/media/tv/tuner/filter/Filter");
 
     std::vector<DemuxFilterEvent::Event> events = filterEvent.events;
     jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
     jobjectArray array = env->NewObjectArray(events.size(), eventClazz, NULL);
 
-    for (int i = 0; i < events.size(); i++) {
-        auto event = events[i];
-        if (event.getDiscriminator() == DemuxFilterEvent::Event::hidl_discriminator::media) {
-            env->SetObjectArrayElement(array, i, getMediaEvent(event));
+    if (!events.empty()) {
+        auto event = events[0];
+        switch (event.getDiscriminator()) {
+            case DemuxFilterEvent::Event::hidl_discriminator::media: {
+                array = getMediaEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::section: {
+                array = getSectionEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::pes: {
+                array = getPesEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
+                array = getTsRecordEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
+                array = getMmtpRecordEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::download: {
+                array = getDownloadEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::ipPayload: {
+                array = getIpPayloadEvent(array, events);
+                break;
+            }
+            case DemuxFilterEvent::Event::hidl_discriminator::temi: {
+                array = getTemiEvent(array, events);
+                break;
+            }
+            default: {
+                break;
+            }
         }
     }
     env->CallVoidMethod(
             mFilter,
-            env->GetMethodID(clazz, "onFilterEvent",
-                    "([Landroid/media/tv/tuner/filter/FilterEvent;)V"),
+            gFields.onFilterEventID,
             array);
     return Void();
 }
 
+
 Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
     ALOGD("FilterCallback::onFilterStatus");
     JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -308,9 +557,16 @@
 
 /////////////// Filter ///////////////////////
 
-Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
+Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    mFilterObj = env->NewWeakGlobalRef(obj);
+}
 
 Filter::~Filter() {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    env->DeleteWeakGlobalRef(mFilterObj);
+    mFilterObj = NULL;
     EventFlag::deleteEventFlag(&mFilterMQEventFlag);
 }
 
@@ -816,6 +1072,37 @@
     return lnbObj;
 }
 
+jobject JTuner::openLnbByName(jstring name) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    std::string lnbName(env->GetStringUTFChars(name, nullptr));
+    sp<ILnb> iLnbSp;
+    Result res;
+    LnbId id;
+    mTuner->openLnbByName(lnbName, [&](Result r, LnbId lnbId, const sp<ILnb>& lnb) {
+        res = r;
+        iLnbSp = lnb;
+        id = lnbId;
+    });
+    if (res != Result::SUCCESS || iLnbSp == nullptr) {
+        ALOGE("Failed to open lnb");
+        return NULL;
+    }
+    mLnb = iLnbSp;
+    sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+    mLnb->setCallback(lnbCb);
+
+    jobject lnbObj = env->NewObject(
+            env->FindClass("android/media/tv/tuner/Lnb"),
+            gFields.lnbInitID,
+            id);
+
+    sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj);
+    lnbSp->incStrong(lnbObj);
+    env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get());
+
+    return lnbObj;
+}
+
 int JTuner::tune(const FrontendSettings& settings) {
     if (mFe == NULL) {
         ALOGE("frontend is not initialized");
@@ -1616,8 +1903,7 @@
 
     jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb");
     gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J");
-    gFields.lnbInitID =
-            env->GetMethodID(lnbClazz, "<init>", "(I)V");
+    gFields.lnbInitID = env->GetMethodID(lnbClazz, "<init>", "(I)V");
 
     jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter");
     gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
@@ -1625,6 +1911,9 @@
             env->GetMethodID(filterClazz, "<init>", "(I)V");
     gFields.onFilterStatusID =
             env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+    gFields.onFilterEventID =
+            env->GetMethodID(filterClazz, "onFilterEvent",
+                    "([Landroid/media/tv/tuner/filter/FilterEvent;)V");
 
     jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
     gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
@@ -1737,6 +2026,12 @@
     return tuner->openLnbById(id);
 }
 
+static jobject android_media_tv_Tuner_open_lnb_by_name(JNIEnv *env, jobject thiz, jstring name) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openLnbByName(name);
+}
+
+
 static jobject android_media_tv_Tuner_open_filter(
         JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
     sp<JTuner> tuner = getTuner(env, thiz);
@@ -2629,6 +2924,8 @@
             (void *)android_media_tv_Tuner_get_lnb_ids },
     { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Lnb;",
             (void *)android_media_tv_Tuner_open_lnb_by_id },
+    { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
+            (void *)android_media_tv_Tuner_open_lnb_by_name },
     { "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Descrambler;",
             (void *)android_media_tv_Tuner_open_descrambler },
     { "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;",
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index fec4cd8..3b8682f 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -114,7 +114,22 @@
     jobject handleToLinearBlock(const native_handle_t* handle, uint32_t size);
 private:
     jweak mFilter;
-    jobject getMediaEvent(const DemuxFilterEvent::Event& event);
+    jobjectArray getSectionEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getMediaEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getPesEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getTsRecordEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getMmtpRecordEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getDownloadEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getIpPayloadEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+    jobjectArray getTemiEvent(
+            jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
 };
 
 struct FrontendCallback : public IFrontendCallback {
@@ -129,7 +144,7 @@
 };
 
 struct Filter : public RefBase {
-    Filter(sp<IFilter> sp, jweak obj);
+    Filter(sp<IFilter> sp, jobject obj);
     ~Filter();
     int close();
     sp<IFilter> getIFilter();
@@ -165,6 +180,7 @@
     int setLna(bool enable);
     jobject getLnbIds();
     jobject openLnbById(int id);
+    jobject openLnbByName(jstring name);
     jobject openFilter(DemuxFilterType type, int bufferSize);
     jobject openTimeFilter();
     jobject openDescrambler();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index c529952..6354ccd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -320,6 +320,15 @@
         public void onCameraAccessPrioritiesChanged() {
             Log.v(TAG, "Camera access permission change");
         }
+        @Override
+        public void onCameraOpened(String cameraId, String clientPackageName) {
+            Log.v(TAG, String.format("Camera %s is opened by client package %s",
+                    cameraId, clientPackageName));
+        }
+        @Override
+        public void onCameraClosed(String cameraId) {
+            Log.v(TAG, String.format("Camera %s is closed", cameraId));
+        }
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 22c3acf..140c075 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,6 +24,7 @@
 import com.android.keyguard.KeyguardViewController;
 import com.android.systemui.car.CarDeviceProvisionedController;
 import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
+import com.android.systemui.car.CarNotificationInterruptionStateProvider;
 import com.android.systemui.dagger.SystemUIRootComponent;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
@@ -40,6 +41,7 @@
 import com.android.systemui.statusbar.car.CarStatusBar;
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -47,6 +49,8 @@
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -63,6 +67,10 @@
 @Module(includes = {DividerModule.class})
 abstract class CarSystemUIModule {
 
+    @Binds
+    abstract NotificationInterruptionStateProvider bindNotificationInterruptionStateProvider(
+            CarNotificationInterruptionStateProvider notificationInterruptionStateProvider);
+
     @Singleton
     @Provides
     @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
@@ -100,6 +108,11 @@
             NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
 
     @Binds
+    @Singleton
+    public abstract BatteryController provideBatteryController(
+            BatteryControllerImpl controllerImpl);
+
+    @Binds
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
new file mode 100644
index 0000000..447e579
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.car;
+
+import android.content.Context;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
+@Singleton
+public class CarNotificationInterruptionStateProvider extends
+        NotificationInterruptionStateProvider {
+
+    @Inject
+    public CarNotificationInterruptionStateProvider(Context context,
+            NotificationFilter filter,
+            StatusBarStateController stateController,
+            BatteryController batteryController) {
+        super(context, filter, stateController, batteryController);
+    }
+
+    @Override
+    public boolean shouldHeadsUp(NotificationEntry entry) {
+        // Because space is usually constrained in the auto use-case, there should not be a
+        // pinned notification when the shade has been expanded. Ensure this by not pinning any
+        // notification if the shade is already opened.
+        if (!getPresenter().isPresenterFullyCollapsed()) {
+            return false;
+        }
+
+        return super.shouldHeadsUp(entry);
+    }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index de768cb..b2e2104 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -95,14 +95,13 @@
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -250,9 +249,10 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
+            NotificationAlertingManager notificationAlertingManager,
             DisplayMetrics displayMetrics,
             MetricsLogger metricsLogger,
             @UiBackground Executor uiBgExecutor,
@@ -335,9 +335,10 @@
                 remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
                 notificationLogger,
-                notificationInterruptStateProvider,
+                notificationInterruptionStateProvider,
                 notificationViewHierarchyManager,
                 keyguardViewMediator,
+                notificationAlertingManager,
                 displayMetrics,
                 metricsLogger,
                 uiBgExecutor,
@@ -487,22 +488,6 @@
                                 .isCurrentUserSetupInProgress();
                     }
                 });
-
-        mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() {
-            @Override
-            public String getName() {
-                return TAG;
-            }
-
-            @Override
-            public boolean suppressInterruptions(NotificationEntry entry) {
-                // Because space is usually constrained in the auto use-case, there should not be a
-                // pinned notification when the shade has been expanded.
-                // Ensure this by not allowing any interruptions (ie: pinning any notifications) if
-                // the shade is already opened.
-                return !getPresenter().isPresenterFullyCollapsed();
-            }
-        });
     }
 
     @Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 9a53584..4754118 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -62,12 +62,13 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationRowModule;
@@ -145,9 +146,10 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
+            NotificationAlertingManager notificationAlertingManager,
             DisplayMetrics displayMetrics,
             MetricsLogger metricsLogger,
             @UiBackground Executor uiBgExecutor,
@@ -232,6 +234,7 @@
                 notificationInterruptionStateProvider,
                 notificationViewHierarchyManager,
                 keyguardViewMediator,
+                notificationAlertingManager,
                 displayMetrics,
                 metricsLogger,
                 uiBgExecutor,
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 3f42ad4..4ea1047 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -2,6 +2,30 @@
 
     name: "SettingsLib",
 
+    defaults: [
+        "SettingsLibDependenciesWithoutWifiTracker",
+    ],
+
+    // TODO(b/149540986): revert this change.
+    static_libs: [
+         // All other dependent components should be put in
+         // "SettingsLibDependenciesWithoutWifiTracker".
+        "WifiTrackerLib",
+    ],
+
+    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
+    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
+
+    resource_dirs: ["res"],
+
+    srcs: ["src/**/*.java", "src/**/*.kt"],
+
+    min_sdk_version: "21",
+
+}
+
+java_defaults {
+    name: "SettingsLibDependenciesWithoutWifiTracker",
     static_libs: [
         "androidx.annotation_annotation",
         "androidx.legacy_legacy-support-v4",
@@ -25,20 +49,9 @@
         "SettingsLibProgressBar",
         "SettingsLibAdaptiveIcon",
         "SettingsLibRadioButtonPreference",
-        "WifiTrackerLib",
         "SettingsLibDisplayDensityUtils",
         "SettingsLibSchedulesProvider",
     ],
-
-    // ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
-    // LOCAL_SHARED_JAVA_LIBRARIES := androidx.lifecycle_lifecycle-common
-
-    resource_dirs: ["res"],
-
-    srcs: ["src/**/*.java", "src/**/*.kt"],
-
-    min_sdk_version: "21",
-
 }
 
 // NOTE: Keep this module in sync with ./common.mk
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 7e78a78..eb0ddfb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -24,6 +24,7 @@
 import static android.media.MediaRoute2Info.TYPE_UNKNOWN;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
 
 import android.app.Notification;
 import android.bluetooth.BluetoothAdapter;
@@ -50,6 +51,7 @@
 public class InfoMediaManager extends MediaManager {
 
     private static final String TAG = "InfoMediaManager";
+    private static final boolean DEBUG = false;
 
     @VisibleForTesting
     final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback();
@@ -339,6 +341,9 @@
 
     private void buildAllRoutes() {
         for (MediaRoute2Info route : mRouterManager.getAllRoutes()) {
+            if (DEBUG) {
+                Log.d(TAG, "buildAllRoutes() route : " + route.getName());
+            }
             if (route.isSystemRoute()) {
                 addMediaDevice(route);
             }
@@ -347,6 +352,9 @@
 
     private void buildAvailableRoutes() {
         for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
+            if (DEBUG) {
+                Log.d(TAG, "buildAvailableRoutes() route : " + route.getName());
+            }
             addMediaDevice(route);
         }
     }
@@ -363,7 +371,8 @@
                 mediaDevice = new InfoMediaDevice(mContext, mRouterManager, route,
                         mPackageName);
                 if (!TextUtils.isEmpty(mPackageName)
-                        && TextUtils.equals(route.getClientPackageName(), mPackageName)) {
+                        && TextUtils.equals(route.getClientPackageName(), mPackageName)
+                        && mCurrentConnectedDevice == null) {
                     mCurrentConnectedDevice = mediaDevice;
                 }
                 break;
@@ -409,12 +418,41 @@
 
         @Override
         public void onRoutesChanged(List<MediaRoute2Info> routes) {
-            refreshDevices();
+            mMediaDevices.clear();
+            mCurrentConnectedDevice = null;
+            if (TextUtils.isEmpty(mPackageName)) {
+                buildAllRoutes();
+            } else {
+                buildAvailableRoutes();
+            }
+
+            final String id = mCurrentConnectedDevice != null
+                    ? mCurrentConnectedDevice.getId()
+                    : null;
+            dispatchConnectedDeviceChanged(id);
         }
 
         @Override
         public void onRoutesRemoved(List<MediaRoute2Info> routes) {
             refreshDevices();
         }
+
+        @Override
+        public void onTransferred(RoutingSessionInfo oldSession, RoutingSessionInfo newSession) {
+            if (DEBUG) {
+                Log.d(TAG, "onTransferred() oldSession : " + oldSession.getName()
+                        + ", newSession : " + newSession.getName());
+            }
+        }
+
+        @Override
+        public void onTransferFailed(RoutingSessionInfo session, MediaRoute2Info route) {
+            dispatchOnRequestFailed(REASON_UNKNOWN_ERROR);
+        }
+
+        @Override
+        public void onRequestFailed(int reason) {
+            dispatchOnRequestFailed(reason);
+        }
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index adb3c11..90f55dd6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -142,20 +142,11 @@
             mCurrentConnectedDevice.disconnect();
         }
 
-        boolean isConnected = false;
         if (TextUtils.isEmpty(mPackageName)) {
-            isConnected = mInfoMediaManager.connectDeviceWithoutPackageName(device);
+            mInfoMediaManager.connectDeviceWithoutPackageName(device);
         } else {
-            isConnected = device.connect();
+            device.connect();
         }
-        if (isConnected) {
-            mCurrentConnectedDevice = device;
-        }
-
-        final int state = isConnected
-                ? MediaDeviceState.STATE_CONNECTED
-                : MediaDeviceState.STATE_DISCONNECTED;
-        dispatchSelectedDeviceStateChanged(device, state);
     }
 
     void dispatchSelectedDeviceStateChanged(MediaDevice device, @MediaDeviceState int state) {
@@ -186,6 +177,12 @@
         }
     }
 
+    void dispatchOnRequestFailed(int reason) {
+        for (DeviceCallback callback : getCallbacks()) {
+            callback.onRequestFailed(reason);
+        }
+    }
+
     /**
      * Stop scan MediaDevice
      */
@@ -337,7 +334,7 @@
         MediaDevice phoneMediaDevice = null;
         for (MediaDevice device : mMediaDevices) {
             if (device instanceof  BluetoothMediaDevice) {
-                if (isConnected(((BluetoothMediaDevice) device).getCachedDevice())) {
+                if (isActiveDevice(((BluetoothMediaDevice) device).getCachedDevice())) {
                     return device;
                 }
             } else if (device instanceof PhoneMediaDevice) {
@@ -347,7 +344,7 @@
         return mMediaDevices.contains(phoneMediaDevice) ? phoneMediaDevice : null;
     }
 
-    private boolean isConnected(CachedBluetoothDevice device) {
+    private boolean isActiveDevice(CachedBluetoothDevice device) {
         return device.isActiveDevice(BluetoothProfile.A2DP)
                 || device.isActiveDevice(BluetoothProfile.HEARING_AID);
     }
@@ -423,20 +420,28 @@
 
         @Override
         public void onConnectedDeviceChanged(String id) {
-            final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+            MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
+            connectDevice = connectDevice != null
+                    ? connectDevice : updateCurrentConnectedDevice();
 
             if (connectDevice == mCurrentConnectedDevice) {
                 Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
                 return;
             }
             mCurrentConnectedDevice = connectDevice;
-            dispatchDeviceAttributesChanged();
+            dispatchSelectedDeviceStateChanged(mCurrentConnectedDevice,
+                    MediaDeviceState.STATE_CONNECTED);
         }
 
         @Override
         public void onDeviceAttributesChanged() {
             dispatchDeviceAttributesChanged();
         }
+
+        @Override
+        public void onRequestFailed(int reason) {
+            dispatchOnRequestFailed(reason);
+        }
     }
 
 
@@ -467,6 +472,18 @@
          * Callback for notifying the device attributes is changed.
          */
         default void onDeviceAttributesChanged() {};
+
+        /**
+         * Callback for notifying that transferring is failed.
+         *
+         * @param reason the reason that the request has failed. Can be one of followings:
+         * {@link android.media.MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+         * {@link android.media.MediaRoute2ProviderService#REASON_REJECTED},
+         * {@link android.media.MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+         * {@link android.media.MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+         * {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+         */
+        default void onRequestFailed(int reason){};
     }
 
     /**
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index 73551f6..e8cbab8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -110,6 +110,12 @@
         }
     }
 
+    protected void dispatchOnRequestFailed(int reason) {
+        for (MediaDeviceCallback callback : getCallbacks()) {
+            callback.onRequestFailed(reason);
+        }
+    }
+
     private Collection<MediaDeviceCallback> getCallbacks() {
         return new CopyOnWriteArrayList<>(mCallbacks);
     }
@@ -158,5 +164,17 @@
          * (e.g: device name, connection state, subtitle) is changed.
          */
         void onDeviceAttributesChanged();
+
+        /**
+         * Callback for notifying that transferring is failed.
+         *
+         * @param reason the reason that the request has failed. Can be one of followings:
+         * {@link android.media.MediaRoute2ProviderService#REASON_UNKNOWN_ERROR},
+         * {@link android.media.MediaRoute2ProviderService#REASON_REJECTED},
+         * {@link android.media.MediaRoute2ProviderService#REASON_NETWORK_ERROR},
+         * {@link android.media.MediaRoute2ProviderService#REASON_ROUTE_NOT_AVAILABLE},
+         * {@link android.media.MediaRoute2ProviderService#REASON_INVALID_COMMAND},
+         */
+        void onRequestFailed(int reason);
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 7cd0a7c..7f93f69 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.settingslib.media;
 
+import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
@@ -54,6 +57,8 @@
     private MediaRouter2Manager mRouterManager;
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
+    @Mock
+    private MediaManager.MediaDeviceCallback mCallback;
 
     private InfoMediaManager mInfoMediaManager;
     private Context mContext;
@@ -144,6 +149,8 @@
     @Test
     public void onRoutesChanged_getAvailableRoutes_shouldAddMediaDevice() {
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
+        mInfoMediaManager.registerCallback(mCallback);
+
         when(info.getId()).thenReturn(TEST_ID);
         when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
 
@@ -160,11 +167,14 @@
         assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
         assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
         assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+        verify(mCallback).onConnectedDeviceChanged(TEST_ID);
     }
 
     @Test
     public void onRoutesChanged_buildAllRoutes_shouldAddMediaDevice() {
         final MediaRoute2Info info = mock(MediaRoute2Info.class);
+        mInfoMediaManager.registerCallback(mCallback);
+
         when(info.getId()).thenReturn(TEST_ID);
         when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
         when(info.isSystemRoute()).thenReturn(true);
@@ -182,6 +192,7 @@
         final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
         assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
         assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+        verify(mCallback).onConnectedDeviceChanged(null);
     }
 
     @Test
@@ -493,4 +504,22 @@
 
         assertThat(mInfoMediaManager.getSessionName()).isEqualTo(TEST_NAME);
     }
+
+    @Test
+    public void onTransferFailed_shouldDispatchOnRequestFailed() {
+        mInfoMediaManager.registerCallback(mCallback);
+
+        mInfoMediaManager.mMediaRouterCallback.onTransferFailed(null, null);
+
+        verify(mCallback).onRequestFailed(REASON_UNKNOWN_ERROR);
+    }
+
+    @Test
+    public void onRequestFailed_shouldDispatchOnRequestFailed() {
+        mInfoMediaManager.registerCallback(mCallback);
+
+        mInfoMediaManager.mMediaRouterCallback.onRequestFailed(REASON_NETWORK_ERROR);
+
+        verify(mCallback).onRequestFailed(REASON_NETWORK_ERROR);
+    }
 }
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 3611dfe..18d8f14 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
@@ -19,7 +19,6 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
@@ -121,8 +120,6 @@
 
         verify(currentDevice).disconnect();
         verify(device).connect();
-        verify(mCallback).onSelectedDeviceStateChanged(any(),
-                eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED));
     }
 
     @Test
@@ -368,7 +365,8 @@
         mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
 
         assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
-        verify(mCallback).onDeviceAttributesChanged();
+        verify(mCallback).onSelectedDeviceStateChanged(device2,
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
     }
 
     @Test
@@ -477,4 +475,13 @@
         assertThat(mLocalMediaManager.mMediaDevices).hasSize(3);
         verify(mCallback).onDeviceListUpdate(any());
     }
+
+    @Test
+    public void onRequestFailed_shouldDispatchOnRequestFailed() {
+        mLocalMediaManager.registerCallback(mCallback);
+
+        mLocalMediaManager.mMediaDeviceCallback.onRequestFailed(1);
+
+        verify(mCallback).onRequestFailed(1);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
index ead2be4..a50965a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -136,4 +136,14 @@
 
         assertThat(device).isNull();
     }
+
+    @Test
+    public void dispatchOnRequestFailed_registerCallback_shouldDispatchCallback() {
+        mMediaManager.registerCallback(mCallback);
+
+        mMediaManager.dispatchOnRequestFailed(1);
+
+        verify(mCallback).onRequestFailed(1);
+    }
+
 }
diff --git a/packages/SettingsProvider/res/values-ta/strings.xml b/packages/SettingsProvider/res/values-ta/strings.xml
index fa6b8cd..54d2242 100644
--- a/packages/SettingsProvider/res/values-ta/strings.xml
+++ b/packages/SettingsProvider/res/values-ta/strings.xml
@@ -20,8 +20,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"அமைப்புகளின் சேமிப்பிடம்"</string>
-    <!-- no translation found for wifi_softap_config_change (5688373762357941645) -->
-    <skip />
-    <!-- no translation found for wifi_softap_config_change_summary (8946397286141531087) -->
-    <skip />
+    <string name="wifi_softap_config_change" msgid="5688373762357941645">"ஹாட்ஸ்பாட் அமைப்புகள் மாற்றப்பட்டன"</string>
+    <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"விவரங்களைப் பார்க்க, தட்டவும்"</string>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index cd62420..2d351c7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -1259,7 +1259,8 @@
         public boolean reset() {
             // overrideableByRestore = true as resetting to default value isn't considered a
             // modification.
-            return update(this.defaultValue, false, packageName, null, true, true);
+            return update(this.defaultValue, false, packageName, null, true, true,
+                    /* resetToDefault */ true);
         }
 
         public boolean isTransient() {
@@ -1272,6 +1273,13 @@
 
         public boolean update(String value, boolean setDefault, String packageName, String tag,
                 boolean forceNonSystemPackage, boolean overrideableByRestore) {
+            return update(value, setDefault, packageName, tag, forceNonSystemPackage,
+                    overrideableByRestore, /* resetToDefault */ false);
+        }
+
+        private boolean update(String value, boolean setDefault, String packageName, String tag,
+                boolean forceNonSystemPackage, boolean overrideableByRestore,
+                boolean resetToDefault) {
             if (NULL_VALUE.equals(value)) {
                 value = null;
             }
@@ -1305,7 +1313,7 @@
             }
 
             // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
-            boolean isPreserved = this.isValuePreservedInRestore || !overrideableByRestore;
+            boolean isPreserved = shouldPreserveSetting(overrideableByRestore, resetToDefault);
 
             // Is something gonna change?
             if (Objects.equals(value, this.value)
@@ -1329,6 +1337,17 @@
                     + " packageName=" + packageName + " tag=" + tag
                     + " defaultFromSystem=" + defaultFromSystem + "}";
         }
+
+        private boolean shouldPreserveSetting(boolean overrideableByRestore,
+                boolean resetToDefault) {
+            if (resetToDefault) {
+                // By default settings are not marked as preserved.
+                return false;
+            }
+
+            // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
+            return this.isValuePreservedInRestore || !overrideableByRestore;
+        }
     }
 
     /**
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index b855d87..6a3c661 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -241,6 +241,18 @@
         assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
     }
 
+    public void testResetSetting_preservedFlagIsReset() {
+        SettingsState settingsState = getSettingStateObject();
+        // Initialize the setting.
+        settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+        // Update the setting so that preserved flag is set.
+        settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE);
+
+        settingsState.resetSettingLocked(SETTING_NAME);
+        assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+
+    }
+
     private SettingsState getSettingStateObject() {
         SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
                 SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e13e49f..8f859b2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -204,7 +204,6 @@
 
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
-    <uses-permission android:name="android.permission.NETWORK_STACK" />
     <!-- Permission needed to test tcp keepalive offload. -->
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
 
@@ -276,6 +275,9 @@
     <!-- Permission needed to test registering pull atom callbacks -->
     <uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM" />
 
+    <!-- Permission needed to modify settings overrideable by restore in CTS tests -->
+    <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
+
     <application android:label="@string/app_label"
                 android:theme="@android:style/Theme.DeviceDefault.DayNight"
                 android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index e066230..0eadcc7 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -46,6 +46,7 @@
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
+        "androidx.viewpager2_viewpager2",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
         "androidx.preference_preference",
@@ -106,6 +107,7 @@
         "SystemUIPluginLib",
         "SystemUISharedLib",
         "SettingsLib",
+        "androidx.viewpager2_viewpager2",
         "androidx.legacy_legacy-support-v4",
         "androidx.recyclerview_recyclerview",
         "androidx.preference_preference",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 30b461d..da93db7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -147,6 +147,7 @@
     <uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
 
     <uses-permission android:name="android.permission.CAMERA" />
+    <uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
 
     <!-- Screen Capturing -->
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
diff --git a/packages/SystemUI/res/layout/controls_dialog_pin.xml b/packages/SystemUI/res/layout/controls_dialog_pin.xml
new file mode 100644
index 0000000..b77d6fa
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_dialog_pin.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:paddingLeft="?android:attr/dialogPreferredPadding"
+    android:paddingRight="?android:attr/dialogPreferredPadding">
+  <EditText
+      android:id="@+id/controls_pin_input"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:hint="@string/controls_pin_instructions"
+      android:inputType="numberPassword" />
+  <CheckBox
+      android:id="@+id/controls_pin_use_alpha"
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:layout_marginTop="5dp"
+      android:text="@string/controls_pin_use_alphanumeric" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml
index 6533c18..34a966c 100644
--- a/packages/SystemUI/res/layout/controls_management.xml
+++ b/packages/SystemUI/res/layout/controls_management.xml
@@ -25,13 +25,40 @@
     android:paddingStart="@dimen/controls_management_side_padding"
     android:paddingEnd="@dimen/controls_management_side_padding" >
 
-    <TextView
-        android:id="@+id/title"
+    <LinearLayout
+        android:orientation="horizontal"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:textSize="@dimen/controls_title_size"
-        android:textAlignment="center" />
+        android:gravity="center_vertical">
+
+        <FrameLayout
+            android:id="@+id/icon_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="start|center_vertical"
+            android:minWidth="56dp"
+            android:visibility="gone"
+            android:paddingTop="@dimen/controls_app_icon_frame_top_padding"
+            android:paddingBottom="@dimen/controls_app_icon_frame_bottom_padding"
+            android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"
+            android:paddingStart="@dimen/controls_app_icon_frame_side_padding" >
+
+            <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="@dimen/controls_app_icon_size"
+                android:layout_height="@dimen/controls_app_icon_size" />
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="@dimen/controls_title_size"
+            android:textAlignment="center" />
+
+    </LinearLayout>
+
 
     <TextView
         android:id="@+id/subtitle"
@@ -41,19 +68,11 @@
         android:textAppearance="?android:attr/textAppearanceSmall"
         android:textAlignment="center" />
 
-    <androidx.core.widget.NestedScrollView
+    <ViewStub
+        android:id="@+id/stub"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:layout_marginTop="@dimen/controls_management_list_margin">
-
-        <ViewStub
-            android:id="@+id/stub"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
-
-    </androidx.core.widget.NestedScrollView>
+        android:layout_weight="1"/>
 
     <FrameLayout
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml
index 2bab433..42d73f3 100644
--- a/packages/SystemUI/res/layout/controls_management_apps.xml
+++ b/packages/SystemUI/res/layout/controls_management_apps.xml
@@ -14,12 +14,18 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-
-<androidx.recyclerview.widget.RecyclerView
+<androidx.core.widget.NestedScrollView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/list"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
+    android:layout_height="0dp"
+    android:layout_weight="1"
+    android:orientation="vertical"
+    android:layout_marginTop="@dimen/controls_management_list_margin">
 
-</androidx.recyclerview.widget.RecyclerView>
\ No newline at end of file
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+    />
+
+</androidx.core.widget.NestedScrollView>
diff --git a/packages/SystemUI/res/layout/controls_management_favorites.xml b/packages/SystemUI/res/layout/controls_management_favorites.xml
index aab32f4..d2ccfcb 100644
--- a/packages/SystemUI/res/layout/controls_management_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_management_favorites.xml
@@ -17,7 +17,7 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="0dp"
     android:orientation="vertical">
 
     <TextView
@@ -29,11 +29,17 @@
         android:gravity="center_horizontal"
     />
 
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/listAll"
-        android:layout_width="match_parent"
+    <com.android.systemui.controls.management.ManagementPageIndicator
+        android:id="@+id/structure_page_indicator"
+        android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:layout_gravity="center"
         android:layout_marginTop="@dimen/controls_management_list_margin"
-        android:nestedScrollingEnabled="false"/>
+        android:visibility="gone" />
+
+    <androidx.viewpager2.widget.ViewPager2
+        android:id="@+id/structure_pager"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
new file mode 100644
index 0000000..2c7e168
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<androidx.core.widget.NestedScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:layout_marginTop="@dimen/controls_management_list_margin">
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/listAll"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+    />
+
+</androidx.core.widget.NestedScrollView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
index ff0c6a7..92ae1b9 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml
@@ -1,71 +1,75 @@
 <?xml version="1.0" encoding="utf-8"?>
-<ScrollView
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/global_actions_container"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-  <androidx.constraintlayout.widget.ConstraintLayout
-      android:id="@+id/global_actions_grid_root"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+>
+  <com.android.systemui.globalactions.GlobalActionsFlatLayout
+      android:id="@id/global_actions_view"
       android:layout_width="match_parent"
-      android:layout_height="match_parent"
+      android:layout_height="wrap_content"
+      android:orientation="horizontal"
+      android:theme="@style/qs_theme"
+      android:gravity="top | center_horizontal"
       android:clipChildren="false"
       android:clipToPadding="false"
-      android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
-      android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset">
-
-    <com.android.systemui.globalactions.GlobalActionsFlatLayout
-        android:id="@id/global_actions_view"
-        android:layout_width="match_parent"
+      android:layout_marginTop="@dimen/global_actions_top_margin"
+  >
+    <LinearLayout
+        android:id="@android:id/list"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
+        android:layout_marginRight="@dimen/global_actions_grid_side_margin"
+        android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
+        android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
+        android:paddingTop="@dimen/global_actions_grid_vertical_padding"
+        android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
         android:orientation="horizontal"
-        android:theme="@style/qs_theme"
-        app:layout_constraintTop_toTopOf="parent"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        android:gravity="top | center_horizontal"
+        android:gravity="left"
+        android:translationZ="@dimen/global_actions_translate"
+    />
+  </com.android.systemui.globalactions.GlobalActionsFlatLayout>
+
+  <com.android.systemui.globalactions.MinHeightScrollView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingBottom="@dimen/global_actions_grid_container_shadow_offset"
+    android:layout_marginBottom="@dimen/global_actions_grid_container_negative_shadow_offset"
+    android:orientation="vertical"
+  >
+    <LinearLayout
+        android:id="@+id/global_actions_grid_root"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
         android:clipChildren="false"
+        android:orientation="vertical"
         android:clipToPadding="false"
-        android:layout_marginTop="@dimen/global_actions_top_margin">
+    >
       <LinearLayout
-          android:id="@android:id/list"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:layout_marginLeft="@dimen/global_actions_grid_side_margin"
-          android:layout_marginRight="@dimen/global_actions_grid_side_margin"
-          android:paddingLeft="@dimen/global_actions_grid_horizontal_padding"
-          android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
-          android:paddingTop="@dimen/global_actions_grid_vertical_padding"
-          android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
-          android:orientation="horizontal"
-          android:gravity="left"
-          android:translationZ="@dimen/global_actions_translate" />
-    </com.android.systemui.globalactions.GlobalActionsFlatLayout>
-
-    <LinearLayout
-        android:id="@+id/global_actions_panel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/global_actions_view">
-
-      <FrameLayout
-          android:id="@+id/global_actions_panel_container"
+          android:id="@+id/global_actions_panel"
           android:layout_width="match_parent"
-          android:layout_height="wrap_content" />
-    </LinearLayout>
+          android:layout_height="wrap_content"
+          android:orientation="vertical"
+      >
+        <FrameLayout
+            android:id="@+id/global_actions_panel_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+        />
+      </LinearLayout>
 
-    <LinearLayout
-        android:id="@+id/global_actions_controls"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical"
-        app:layout_constraintLeft_toLeftOf="parent"
-        app:layout_constraintRight_toRightOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/global_actions_panel"
-        app:layout_constraintBottom_toBottomOf="parent" />
-  </androidx.constraintlayout.widget.ConstraintLayout>
-</ScrollView>
+      <LinearLayout
+          android:id="@+id/global_actions_controls"
+          android:layout_width="match_parent"
+          android:layout_height="wrap_content"
+          android:orientation="vertical"
+          android:layout_marginRight="@dimen/global_actions_grid_horizontal_padding"
+          android:layout_marginLeft="@dimen/global_actions_grid_horizontal_padding"
+      />
+    </LinearLayout>
+  </com.android.systemui.globalactions.MinHeightScrollView>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml
deleted file mode 100644
index d441070..0000000
--- a/packages/SystemUI/res/layout/global_actions_wrapped.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.android.systemui.HardwareUiLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@id/global_actions_view"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_gravity="top|right"
-    android:layout_marginBottom="0dp"
-    android:orientation="vertical"
-    android:paddingTop="@dimen/global_actions_top_padding"
-    android:clipToPadding="false"
-    android:theme="@style/qs_theme"
-    android:clipChildren="false">
-
-    <!-- Global actions is right-aligned to be physically near power button -->
-    <LinearLayout
-        android:id="@android:id/list"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|right"
-        android:gravity="center"
-        android:orientation="vertical"
-        android:padding="@dimen/global_actions_padding"
-        android:translationZ="@dimen/global_actions_translate" />
-
-    <!-- For separated button-->
-    <FrameLayout
-        android:id="@+id/separated_button"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top|right"
-        android:layout_marginTop="6dp"
-        android:gravity="center"
-        android:orientation="vertical"
-        android:padding="@dimen/global_actions_padding"
-        android:translationZ="@dimen/global_actions_translate" />
-
-</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 02104f5..9ba891d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> bestuur jou werkprofiel. Die profiel is gekoppel aan <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, wat jou netwerkaktiwiteit, insluitend e-posse, programme en webwerwe, kan monitor.\n\nJy is ook gekoppel aan <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, wat jou persoonlike netwerkaktiwiteit kan monitor."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontsluit gehou deur TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Toestel sal gesluit bly totdat jy dit handmatig ontsluit"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Kry kennisgewings vinniger"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Sien hulle voordat jy ontsluit"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nee, dankie"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Beweeg na links onder"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Beweeg na regs onder"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Maak toe"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hou kletse prominent"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nuwe kletse van <xliff:g id="APP_NAME">%1$s</xliff:g> af sal as borrels verskyn. Tik op \'n borrel om dit oop te maak. Sleep om dit te skuif.\n\nTik op die borrel"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Bestuur om borrels vanaf hierdie program af te skakel"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Stelselnavigasie is opgedateer. Gaan na Instellings toe om veranderinge te maak."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gaan na Instellings toe om stelselnavigasie op te dateer"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Bystandmodus"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Almal"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Die lys met alle kontroles kon nie gelaai word nie."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Ander"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 22df519..a73d48d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"የእርስዎ የሥራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> የሚተዳደር ነው። መገለጫው ኢሜይሎችን፣ መተግበሪያዎችን፣ እና የድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴን መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝቷል።\n\nበተጨማሪ የእርስዎን የግል የአውታረ መረብ እንቅስቃሴ መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"በ TrustAgent እንደተከፈተ ቀርቷል"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"እራስዎ እስኪከፍቱት ድረስ መሣሪያ እንደተቆለፈ ይቆያል"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ማሳወቂያዎችን ፈጥነው ያግኙ"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ከመክፈትዎ በፊት ይመልከቷቸው"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"አይ፣ አመሰግናለሁ"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"የግርጌውን ግራ አንቀሳቅስ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"አሰናብት"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ውይይቶችን ከፊት ያድርጓቸው"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"ከ<xliff:g id="APP_NAME">%1$s</xliff:g> የመጡ አዲስ ውይይቶች እንደ አረፋዎች ሆነው ይታያሉ። አንድ አረፋን ለመክፈት መታ ያድርጉት። እሱን ለማንቀሳቀስ ይጎትቱት።\n\nአረፋውን መታ ያድርጉት"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"የዚህ መተግበሪያ አረፋዎችን ለማጥፋት አቀናብርን መታ ያድርጉ"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"የስርዓት ዳሰሳ ተዘምኗል። ለውጦችን ለማድረግ ወደ ቅንብሮች ይሂዱ።"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"የስርዓት ዳሰሳን ለማዘመን ወደ ቅንብሮች ይሂዱ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ተጠባባቂ"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ሁሉም"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"የሁሉም መቆጣጠሪያዎች ዝርዝር ሊጫን አልተቻለም።"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ሌላ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ee0c65f..37f6911 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -62,7 +62,7 @@
     <string name="usb_debugging_always" msgid="4003121804294739548">"السماح دائمًا من هذا الكمبيوتر"</string>
     <string name="usb_debugging_allow" msgid="1722643858015321328">"سماح"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"‏لا يُسمح بتصحيح أخطاء USB"</string>
-    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"‏لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تشغيل تصحيح أخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
+    <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"‏لا يمكن للمستخدم الذي يسجّل دخوله حاليًا إلى هذا الجهاز تفعيل تصحيح الأخطاء USB. لاستخدام هذه الميزة، يمكنك التبديل إلى المستخدم الأساسي."</string>
     <string name="wifi_debugging_title" msgid="7300007687492186076">"‏هل تريد السماح باستخدام ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\" على هذه الشبكة؟"</string>
     <string name="wifi_debugging_message" msgid="5461204211731802995">"‏اسم الشبكة (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nعنوان شبكة Wi‑Fi (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
     <string name="wifi_debugging_always" msgid="2968383799517975155">"السماح باستخدام هذه الميزة على هذه الشبكة دائمًا"</string>
@@ -570,12 +570,13 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"يخضع الملف الشخصي للعمل لإدارة <xliff:g id="ORGANIZATION">%1$s</xliff:g>. تم ربط هذا الملف الشخصي بـ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>، الذي يمكنه مراقبة أنشطة شبكتك، بما في ذلك الرسائل الإلكترونية والتطبيقات ومواقع الويب.\n\nتم ربطك بـ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>، الذي يمكنه مراقبة أنشطة شبكتك الشخصية."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‏فتح القفل باستمرار بواسطة TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"سيظل الجهاز مقفلاً إلى أن يتم فتح قفله يدويًا"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"الحصول على الإشعارات بشكل أسرع"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"الاطّلاع عليها قبل فتح القفل"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"لا، شكرًا"</string>
     <string name="hidden_notifications_setup" msgid="2064795578526982467">"إعداد"</string>
     <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
-    <string name="volume_zen_end_now" msgid="5901885672973736563">"إيقاف التشغيل الآن"</string>
+    <string name="volume_zen_end_now" msgid="5901885672973736563">"إيقاف التفعيل الآن"</string>
     <string name="accessibility_volume_settings" msgid="1458961116951564784">"إعدادات الصوت"</string>
     <string name="accessibility_volume_expand" msgid="7653070939304433603">"توسيع"</string>
     <string name="accessibility_volume_collapse" msgid="2746845391013829996">"تصغير"</string>
@@ -779,7 +780,7 @@
     <string name="keyboard_key_media_stop" msgid="1509943745250377699">"إيقاف"</string>
     <string name="keyboard_key_media_next" msgid="8502476691227914952">"التالي"</string>
     <string name="keyboard_key_media_previous" msgid="5637875709190955351">"السابق"</string>
-    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"إرجاع"</string>
+    <string name="keyboard_key_media_rewind" msgid="3450387734224327577">"ترجيع"</string>
     <string name="keyboard_key_media_fast_forward" msgid="3572444327046911822">"تقديم سريع"</string>
     <string name="keyboard_key_page_up" msgid="173914303254199845">"Page Up"</string>
     <string name="keyboard_key_page_down" msgid="9035902490071829731">"Page Down"</string>
@@ -999,12 +1000,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"الاحتفاظ بالمحادثات في المقدمة"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"ستظهر المحادثات الجديدة من <xliff:g id="APP_NAME">%1$s</xliff:g> كفقاقيع. انقر على فقعة لفتحها. اسحبها لنقلها.\n\nانقر على الفقاعة."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"انقر على \"إدارة\" لإيقاف الفقاعات من هذا التطبيق."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"تم تحديث التنقل داخل النظام. لإجراء التغييرات، يُرجى الانتقال إلى \"الإعدادات\"."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"الانتقال إلى \"الإعدادات\" لتعديل التنقل داخل النظام"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"وضع الاستعداد"</string>
@@ -1028,4 +1026,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"الكل"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"تعذّر تحميل قائمة كل عناصر التحكّم."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"غير ذلك"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index a1a6ae9..2dc93cd 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g>য়ে আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল পৰিচালনা কৰে। এই প্ৰ\'ফাইলটো <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>ৰে সংযুক্ত হৈ আছে যি ইমেইল, এপ্ আৰু ৱেবছাইটসমূহকে ধৰি আপোনাৰ কর্মস্থানৰ নেটৱর্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰিব। \n\nআপুনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>ৰ সৈতেও সংযুক্ত হৈ আছে, যি আপোনাৰ ব্য়ক্তিগত নেটৱৰ্কৰ কাৰ্যকলাপ নিৰীক্ষণ কৰিব পাৰে।"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgentএ আনলক কৰি ৰাখিছে"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"আপুনি নিজে আনলক নকৰালৈকে ডিভাইচ লক হৈ থাকিব"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"জাননী ক্ষিপ্ৰতাৰে লাভ কৰক"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"আপুনি আনলক কৰাৰ পূৰ্বে তেওঁলোকক চাওক"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"নালাগে, ধন্যবাদ"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"বুটামটো বাওঁফালে নিয়ক"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"চাটসমূহ সন্মুখত ৰাখক"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ নতুন চাটসমূহ বাবল হিচাপে দেখা পোৱা যাব। এইটো খুলিবলৈ এটা বাবলত টিপক। এইটোক আঁতৰাবলৈ টানি আনক।\n\nবাবলটোত টিপক"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই এপ্‌টোৰ পৰা বাবল অফ কৰিবলৈ পৰিচালনা কৰকত টিপক"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰা হ’ল। সলনি কৰিবলৈ ছেটিংসমূহ-লৈ যাওক।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ছিষ্টেম নেভিগেশ্বন আপডে’ট কৰিবলৈ ছেটিংসমূহ-লৈ যাওক"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ষ্টেণ্ডবাই"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ক্ষিপ্ৰ নিয়ন্ত্ৰণসমূহ"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"নিয়ন্ত্ৰণসমূহ যোগ দিয়ক"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"এটা এপ্ বাছনি কৰক, যিটোৰ পৰা নিয়ন্ত্ৰণসমূহ যোগ দিয়া হ\'ব"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> টা নিয়ন্ত্ৰণ যোগ কৰা হ’ল।</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> টা নিয়ন্ত্ৰণ যোগ কৰা হ’ল।</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্ৰণসমূহ"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"ক্ষিপ্ৰ এক্সেছৰ বাবে নিয়ন্ত্ৰণসমূহ বাছনি কৰক"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"প্ৰিয়সমূহ"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"সকলো"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"নিয়ন্ত্ৰণসমূহৰ সম্পূর্ণ সূচীখন ল’ড কৰিব পৰা নগ’ল।"</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 289838e..f116289 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"İş profili <xliff:g id="ORGANIZATION">%1$s</xliff:g> tərəfindən idarə edilir. Profil e-poçt, tətbiq və veb saytlar da daxil olmaqla şəbəkə fəaliyyətinə nəzarət edən <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> tətbiqinə qoşuludur.\n\nEyni zamanda şəxsi şəbəkə fəaliyyətinə nəzarət edən <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> tətbiqinə qoşulusunuz."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ilə açıq saxlayın"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirişləri daha sürətlə əldə edin"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Kiliddən çıxarmadan öncə onları görün"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Yox, çox sağ olun"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Aşağıya sola köçürün"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Söhbətləri öndə saxlayın"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Yeni <xliff:g id="APP_NAME">%1$s</xliff:g> söhbətləri qabarcıq şəklində görünəcək. Açmaq üçün qabarcığa toxunun. Hərəkət etdirmək üçün onu sürüşdürün.\n\nQabarcığa toxunun"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu tətbiqdə qabarcıqları deaktiv etmək üçün \"İdarə edin\" seçiminə toxunun"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistem naviqasiyası yeniləndi. Dəyişiklik etmək üçün Ayarlara daxil olun."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistem naviqasiyasını yeniləmək üçün Ayarlara keçin"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gözləmə rejimi"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Hamısı"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Bütün nizamlayıcıların siyahısı yüklənmədi."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Digər"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index b690829..ac8d937 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent sprečava zaključavanje"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Brže dobijajte obaveštenja"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Pregledajte ih pre otključavanja"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -984,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premesti dole levo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premesti dole desno"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Neka poruke ćaskanja ostanu u prvom planu"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nove poruke ćaskanja iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> će se prikazati kao oblačići. Dodirnite oblačić da biste ga otvorili. Prevucite da biste ga premestili.\n\nDodirnite oblačić"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigacija sistema je ažurirana. Da biste uneli izmene, idite u Podešavanja."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Podešavanja da biste ažurirali navigaciju sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravnosti"</string>
@@ -1010,4 +1008,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspelo."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index feee6a2..29d76a6 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -566,6 +566,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ваш працоўны профіль знаходзіцца пад кіраваннем <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ён падключаны да праграмы <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, якая можа сачыць за вашай працоўнай сеткавай актыўнасцю, уключаючы электронную пошту, праграмы і вэб-сайты.\n\nВы таксама падключаны да праграмы <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, якая можа сачыць за вашай асабістай сеткавай актыўнасцю."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Разблакіравана з дапамогай TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Прылада будзе заставацца заблакіраванай, пакуль вы не разблакіруеце яе ўручную"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Атрымлівайце апавяшчэнні хутчэй"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Праглядайце іх перад разблакіроўкай"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Не, дзякуй"</string>
@@ -991,12 +992,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перамясціць лявей і ніжэй"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перамясціць правей і ніжэй"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Адхіліць"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Пакідаць чаты на экране"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новыя чаты з праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будуць паказвацца ў выглядзе ўсплывальных апавяшчэнняў. Каб адкрыць усплывальнае апавяшчэнне, націсніце на яго. Каб перамясціць – перацягніце.\n\nНацісніце на ўсплывальнае апавяшчэнне"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальная апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацыя ў сістэме абноўлена. Каб унесці змяненні, перайдзіце ў Налады."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перайдзіце ў Налады, каб абнавіць параметры навігацыі ў сістэме"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Рэжым чакання"</string>
@@ -1018,4 +1016,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Усе"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не ўдалося загрузіць спіс усіх сродкаў кіравання."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Іншае"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index fa57d28..efb5b07 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Служебният ви потребителски профил се управлява от <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Той е свързан с приложението <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, което може да наблюдава служебната ви активност в мрежата, включително имейли, приложения и уебсайтове.\n\nУстановена е връзка и с приложението <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, което може да наблюдава личната ви активност в мрежата."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Поддържа се отключено от надежден агент"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Устройството ще остане заключено, докато не го отключите ръчно"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Получавайте известия по-бързо"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Вижте известията, преди да отключите"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Няма нужда"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Преместване долу вляво"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Преместване долу вдясно"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отхвърляне"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Задръжте чатовете на екрана"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новите чатове от <xliff:g id="APP_NAME">%1$s</xliff:g> ще се показват като балончета. Докоснете някое, за да го отворите. Плъзнете, за да го преместите.\n\nДокоснете балончето"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Докоснете „Управление“, за да изключите балончетата от това приложение"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Режимът за навигиране в системата е актуализиран. За да извършите промени, отворете настройките."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Отворете настройките, за да актуализирате режима за навигиране в системата"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим на готовност"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Всички"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Списъкът с всички контроли не бе зареден."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 1f6a377..7c0701f 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক অ্যাক্টিভিটির উপরে নজর রাখতে পারে।\n\n এ ছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত, যেটি আপনার ব্যক্তিগত নেটওয়ার্কে নজর রাখে।"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent দিয়ে আনলক করে রাখা হয়েছে"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"বিজ্ঞপ্তিগুলি আরও দ্রুত পান"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"আপনি আনলক করার আগে ওগুলো দেখুন"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"না থাক"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"চ্যাটগুলি সামনে রাখুন"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর তরফ থেকে নতুন চ্যাট বাবল হিসেবে দেখানো হবে। এটি খোলার জন্য বাবল ট্যাপ করুন। এটি সরানোর জন্য টেনে আনুন।\n\nবাবল ট্যাপ করুন"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"এই অ্যাপ থেকে বাবল বন্ধ করতে ম্যানেজ করুন বিকল্প ট্যাপ করুন"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"দ্রুত নিয়ন্ত্রণ"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"কন্ট্রোল যোগ করুন"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"এমন একটি অ্যাপ বাছুন যেটি থেকে কন্ট্রোল যোগ করা যাবে"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g>টি কন্ট্রোল যোগ করা হয়েছে।</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>টি কন্ট্রোল যোগ করা হয়েছে।</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"নিয়ন্ত্রণ"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"দ্রুত অ্যাক্সেস করার জন্য কন্ট্রোল বেছে নিন"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"পছন্দসই"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"সব"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"সব কন্ট্রোলের তালিকা লোড করা যায়নি।"</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"অন্য"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index fcc3680..ce6fe52 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Radnim profilom upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može pratiti vašu aktivnost na radnoj mreži, uključujući e-poruke, aplikacije i web lokacije.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može pratiti vašu aktivnost na privatnoj mreži."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pouzdani agent sprečava zaključavanje"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Brže primaj obavještenja"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Vidi ih prije otključavanja"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -986,12 +987,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pomjeri dolje lijevo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pomjerite dolje desno"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zadržite chatove u prvom planu"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi chatovi iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> će se prikazati u oblačićima. Dodirnite oblačić da ga otvorite. Prevucite da ga premjestite.\n\nDodirnite oblačić"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljaj da isključite oblačiće iz ove aplikacije"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigiranje sistemom je ažurirano. Da izvršite promjene, idite u Postavke."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Idite u Postavke da ažurirate navigiranje sistemom"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
@@ -1012,4 +1010,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Učitavanje liste svih kontrola nije uspjelo."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7f7eff1..f6f89fd 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona el teu perfil de treball. El perfil està connectat a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pot supervisar la teva activitat a la xarxa de treball, com ara els correus electrònics, les aplicacions i els llocs web.\n\nTambé estàs connectat a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pot supervisar la teva activitat personal a la xarxa."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloquejat per TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositiu continuarà bloquejat fins que no el desbloquegis manualment."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Rep notificacions més ràpidament"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Mostra-les abans de desbloquejar"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gràcies"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mou a baix a l\'esquerra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mou a baix a la dreta"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Omet"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantén els xats a la vista"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Els xats nous de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> es mostraran en forma de bombolles. Toca una bombolla per obrir-la. Arrossega-la per moure-la.\n\nToca la bombolla"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestiona per desactivar les bombolles d\'aquesta aplicació"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"S\'ha actualitzat el sistema de navegació. Per fer canvis, ves a Configuració."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ves a Configuració per actualitzar el sistema de navegació"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tots"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"No s\'ha pogut carregar la llista completa de controls."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altres"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 8d26c4a..63290521 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Váš pracovní profil spravuje organizace <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je připojen k aplikaci <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, která může sledovat vaši aktivitu v síti, včetně e-mailů, aplikací a webů.\n\nTaké jste připojeni k aplikaci <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, která může sledovat vaši osobní aktivitu v síti."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odemknutí udržováno funkcí TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Zařízení zůstane uzamčeno, dokud je ručně neodemknete"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Čtěte si oznámení rychleji"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Můžete si je přečíst před odemčením obrazovky."</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, děkuji"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Přesunout vlevo dolů"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Přesunout vpravo dolů"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavřít"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zobrazovat chaty v popředí"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nové chaty z aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> se budou zobrazovat jako bubliny. Bublinu otevřete klepnutím. Přetažením ji přemístíte.\n\nKlepnout na bublinu"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bubliny pro tuto aplikaci můžete vypnout klepnutím na Spravovat"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systémová navigace byla aktualizována. Chcete-li provést změny, přejděte do Nastavení."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Přejděte do Nastavení a aktualizujte systémovou navigaci"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostní režim"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Vše"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Načtení seznamu všech ovládacích prvků se nezdařilo."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Jiné"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 1ad3102..bb2f57a 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen har forbindelse til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. mails, apps og websites.\n\nDu har også forbindelse til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din personlige netværksaktivitet."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes oplåst af TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Modtag notifikationer hurtigere"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Se dem, før du låser op"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nej tak"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flyt ned til venstre"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flyt ned til højre"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Afvis"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hold chatsamtaler i forgrunden"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nye chatsamtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som bobler. Tryk på en boble for at åbne samtalen. Træk boblen for at flytte den.\n\nTryk på boblen"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tryk på Administrer for at deaktivere bobler fra denne app"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigationen blev opdateret. Gå til Indstillinger for at foretage ændringer."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Indstillinger for at opdatere systemnavigationen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over styringselementer kunne ikke indlæses."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andre"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4978041..bfbc735 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -562,6 +562,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Dein Arbeitsprofil wird von <xliff:g id="ORGANIZATION">%1$s</xliff:g> verwaltet. Das Profil ist mit <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> verknüpft. Diese App kann deine Netzwerkaktivitäten überwachen, einschließlich E-Mails, Apps und Websites.\n\nDu bist auch mit <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> verbunden, die deine persönlichen Netzwerkaktivitäten überwachen kann."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Durch TrustAgent entsperrt"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Das Gerät bleibt gesperrt, bis du es manuell entsperrst."</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Benachrichtigungen schneller erhalten"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Vor dem Entsperren anzeigen"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nein danke"</string>
@@ -983,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Nach unten links verschieben"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Nach unten rechts verschieben"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Schließen"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chats im Vordergrund behalten"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Neue <xliff:g id="APP_NAME">%1$s</xliff:g>-Chats werden als Bubbles angezeigt. Wenn du eine Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, ziehe an ihr.\n\nTippe die Bubble an."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tippe auf \"Verwalten\", um Bubbles für diese App zu deaktivieren"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemsteuerungseinstellungen wurden angepasst. Änderungen kannst du in den Einstellungen vornehmen."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gehe zu den Einstellungen, um die Systemsteuerung anzupassen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1008,4 +1007,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Fehler beim Laden der Liste mit Steuerelementen."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Andere"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 3eab4dd..f0b0934 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ο οργανισμός <xliff:g id="ORGANIZATION">%1$s</xliff:g> διαχειρίζεται το προφίλ εργασίας σας. Το προφίλ συνδέεται με την εφαρμογή <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, η οποία μπορεί να παρακολουθεί τη δραστηριότητα του δικτύου της εργασίας σας, συμπεριλαμβανομένων μηνυμάτων ηλεκτρονικού ταχυδρομείου, εφαρμογών και ιστοτόπων.\n\nΕπίσης, είστε συνδεδεμένοι στην εφαρμογή <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, που έχει τη δυνατότητα παρακολούθησης της δραστηριότητας του προσωπικού σας δικτύου."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Διατήρηση ξεκλειδώματος με TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Η συσκευή θα παραμείνει κλειδωμένη μέχρι να την ξεκλειδώσετε μη αυτόματα"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Λάβετε ειδοποιήσεις γρηγορότερα"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Εμφάνιση πριν το ξεκλείδωμα"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Όχι"</string>
@@ -1001,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Όλα"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ανεπιτυχής φόρτωση λίστας όλων των στοιχ. ελέγχου."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Άλλο"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 98fcd53..c560b17 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+    <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+    <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+    <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index dbdff59..91d0d74 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+    <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+    <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+    <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 98fcd53..c560b17 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+    <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+    <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+    <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 98fcd53..c560b17 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Your work profile is managed by <xliff:g id="ORGANIZATION">%1$s</xliff:g>. The profile is connected to <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, which can monitor your work network activity, including emails, apps and websites.\n\nYou\'re also connected to <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, which can monitor your personal network activity."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Kept unlocked by trust agent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Get notifications faster"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"See them before you unlock"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, thanks"</string>
@@ -1001,4 +1002,7 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"All"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"The list of all controls could not be loaded."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Other"</string>
+    <string name="controls_dialog_title" msgid="8806193219278278442">"Add to Quick Controls"</string>
+    <string name="controls_dialog_ok" msgid="7011816381344485651">"Add to favourites"</string>
+    <string name="controls_dialog_message" msgid="6292099631702047540">"<xliff:g id="APP">%s</xliff:g> suggested this control to add to your favourites."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 8b6a7eb..4c83c13 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎Your work profile is managed by ‎‏‎‎‏‏‎<xliff:g id="ORGANIZATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎. The profile is connected to ‎‏‎‎‏‏‎<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎, which can monitor your work network activity, including emails, apps, and websites.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎You\'re also connected to ‎‏‎‎‏‏‎<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>‎‏‎‎‏‏‏‎, which can monitor your personal network activity.‎‏‎‎‏‎"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‎Kept unlocked by TrustAgent‎‏‎‎‏‎"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎Device will stay locked until you manually unlock‎‏‎‎‏‎"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="POWER_INDICATION">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‏‏‏‏‏‎‏‏‎Get notifications faster‎‏‎‎‏‎"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‎See them before you unlock‎‏‎‎‏‎"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎No thanks‎‏‎‎‏‎"</string>
@@ -1001,4 +1002,7 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎All‎‏‎‎‏‎"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎The list of all controls could not be loaded.‎‏‎‎‏‎"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎Other‎‏‎‎‏‎"</string>
+    <string name="controls_dialog_title" msgid="8806193219278278442">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‎‎Add to Quick Controls‎‏‎‎‏‎"</string>
+    <string name="controls_dialog_ok" msgid="7011816381344485651">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎Add to favorites‎‏‎‎‏‎"</string>
+    <string name="controls_dialog_message" msgid="6292099631702047540">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP">%s</xliff:g>‎‏‎‎‏‏‏‎ suggested this control to add to your favorites.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f5c7808..979e4ab 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> administra tu perfil de red. El perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede controlar tu actividad de red de trabajo, incluidos los correos electrónicos, las apps y los sitios web.\n\nTambién estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede controlar tu actividad de red personal."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent lo mantiene desbloqueado"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositivo permanecerá bloqueado hasta que lo desbloquees manualmente."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Recibe notificaciones más rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gracias"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ubicar abajo a la izquierda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ubicar abajo a la derecha"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantener los chats a la vista"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Los chats nuevos de <xliff:g id="APP_NAME">%1$s</xliff:g> se mostrarán como burbujas. Presiona una burbuja para abrirla. Arrástrala para moverla.\n\nPresiona la burbuja"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Presiona Administrar para desactivar las burbujas de esta app"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Todo"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"No se cargó la lista completa de controles."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 85af824..c58ec87 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> gestiona tu perfil de trabajo. El perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que puede supervisar tu actividad de red profesional, como los correos electrónicos, las aplicaciones y los sitios web.\n\nTambién te has conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que puede supervisar tu actividad de red personal."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"El dispositivo permanecerá bloqueado hasta que se desbloquee manualmente"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Recibe notificaciones más rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, gracias"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover abajo a la izquierda."</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover abajo a la derecha"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cerrar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantén los chats a la vista"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Los nuevos chats de <xliff:g id="APP_NAME">%1$s</xliff:g> se mostrarán como burbujas. Toca una burbuja para abrirla. Arrástrala para moverla.\n\nToca la burbuja"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se ha actualizado la navegación del sistema. Para hacer cambios, ve a Ajustes."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Ajustes para actualizar la navegación del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"No se ha podido cargar la lista de los controles."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Otros"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 548076d..bb15e29 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Teie tööprofiili haldab <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profiil on ühendatud rakendusega <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, mis saab jälgida teie töökoha võrgutegevusi, sh meile, rakendusi ja veebisaite.\n\nOlete ühendatud ka rakendusega <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, mis saab jälgida teie isiklikke võrgutegevusi."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Avatuna hoiab TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Seade jääb lukku, kuni selle käsitsi avate"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Saate märguandeid kiiremini"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Näete neid enne avamist"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tänan, ei"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Teisalda alla vasakule"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Teisalda alla paremale"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loobu"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Hoia vestlused esiplaanil"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Uued vestlused rakendusest <xliff:g id="APP_NAME">%1$s</xliff:g> kuvatakse mullidena. Selle avamiseks puudutage mulli. Teisaldamiseks lohistage.\n\nPuudutage mulli"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Selle rakenduse puhul mullide väljalülitamiseks puudutage valikut Haldamine"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Süsteemis navigeerimine on värskendatud. Muutmiseks avage jaotis Seaded."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Süsteemi navigeerimise värskendamiseks avage jaotis Seaded"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ooterežiim"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Kõik"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kõikide juhtelementide loendit ei saanud laadida."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 380b752..5961e52 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> erakundeak kudeatzen dizu laneko profila. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> aplikaziora dago konektatuta profila, eta aplikazio horrek sarean egiten dituzun jarduerak kontrola ditzake, mezu elektronikoak, aplikazioak eta webguneak barne. \n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> aplikaziora ere zaude konektatuta, eta hark sare pertsonalean egiten dituzun jarduerak kontrola ditzake."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent bidez desblokeatuta"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Gailua blokeatuta egongo da eskuz desblokeatu arte"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Eskuratu jakinarazpenak azkarrago"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ikusi desblokeatu baino lehen"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ez, eskerrik asko"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Eraman behealdera, ezkerretara"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Eraman behealdera, eskuinetara"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Baztertu"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Utzi txatak aurrealdean"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren txat berriak burbuila gisa agertuko dira. Burbuilak irekitzeko, saka itzazu. Mugitzeko, berriz, arrasta itzazu.\n\nSakatu burbuila"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Aplikazioaren burbuilak desaktibatzeko, sakatu Kudeatu"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Eguneratu da sistemaren nabigazioa. Aldaketak egiteko, joan Ezarpenak atalera."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemaren nabigazioa eguneratzeko, joan Ezarpenak atalera"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Egonean"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Guztiak"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ezin izan da kargatu kontrol guztien zerrenda."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Beste bat"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index c7c0336..b2c0d2e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -498,7 +498,7 @@
     <string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمه‌ها"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلان‌های بی‌صدا"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلان‌ها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string>
-    <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع شود"</string>
+    <string name="media_projection_action_text" msgid="3634906766918186440">"اکنون شروع کنید"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"اعلانی موجود نیست"</string>
     <string name="profile_owned_footer" msgid="2756770645766113964">"شاید نمایه کنترل شود"</string>
     <string name="vpn_footer" msgid="3457155078010607471">"ممکن است شبکه کنترل شود"</string>
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این نمایه به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند تنظیمات، دسترسی شرکتی، برنامه‌ها، داده‌های مرتبط با دستگاه و اطلاعات مکان دستگاه شما را پایش کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت خصوصی شما را در شبکه پایش کند."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"‏با TrustAgent قفل را باز نگه‌دارید"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"دریافت سریع‌تر اعلان‌ها"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"قبل از باز کردن قفل آنها را مشاهده کنید"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"نه متشکرم"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"انتقال به پایین سمت راست"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"انتقال به پایین سمت چپ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"رد کردن"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"نگه داشتن گپ‌ها در جلو"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"گپ‌های جدید از <xliff:g id="APP_NAME">%1$s</xliff:g> به‌صورت «حباب» نمایش داده می‌شوند. روی «حباب» ضربه بزنید تا باز شود. آن را بکشید تا جابه‌جا شود.\n\nروی «حباب» ضربه بزنید"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"برای خاموش کردن «حباب‌ها» از این برنامه، روی «مدیریت» ضربه بزنید"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"پیمایش سیستم به‌روزرسانی شد. برای انجام تغییرات به «تنظیمات» بروید."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"برای به‌روزرسانی پیمایش سیستم، به «تنظیمات» بروید"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"آماده‌به‌کار"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"همه"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"فهرست همه کنترل‌ها را نمی‌توان بارگیری کرد."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"موارد دیگر"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 0daab9e..86c6e7c 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> hallinnoi työprofiiliasi. Se on yhteydessä sovellukseen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, joka voi valvoa toimintaasi verkossa, esimerkiksi sähköposteja, sovelluksia ja verkkosivustoja.\n\nLisäksi olet yhteydessä sovellukseen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, joka voi valvoa henkilökohtaista toimintaasi verkossa."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent pitää lukitusta avattuna"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Laite pysyy lukittuna, kunnes se avataan käsin"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Näe ilmoitukset nopeammin"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Näytä ennen lukituksen avaamista"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ei kiitos"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Siirrä vasempaan alareunaan"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Siirrä oikeaan alareunaan"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ohita"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Säilytä chatit etualalla"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Sovelluksen <xliff:g id="APP_NAME">%1$s</xliff:g> uudet chatit näkyvät ohjekuplina. Kosketa ohjekuplaa avataksesi sen. Siirrä sitä vetämällä.\n\n Kosketa ohjekuplaa."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Valitse Hallinnoi, jos haluat poistaa ohjekuplat käytöstä tästä sovelluksesta"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Järjestelmän navigointitapa vaihdettu. Voit muuttaa sitä asetuksista."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Vaihda järjestelmän navigointitapaa asetuksista"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Virransäästötila"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Kaikki"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kaikkien säätimien luetteloa ei voitu ladata."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Muu"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index cc9b7c2..2c5da71 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ce profil est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, qui peut contrôler votre activité professionnelle sur le réseau, y compris l\'activité relative aux courriels, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, qui peut contrôler votre activité personnelle sur le réseau."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Voir les notifications plus rapidement"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, merci"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer dans coin inf. gauche"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer dans coin inf. droit"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Fermer"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Garder les messages de clavardage à l\'avant"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Les nouveaux messages de clavardage de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'afficheront sous forme de bulles. Pour ouvrir une bulle, touchez-la. Pour la déplacer, faites-la glisser.\n\nTouchez la bulle"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toucher Gérer pour désactiver les bulles de cette application"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"La navigation système a été mise à jour. Pour apporter des modifications, accédez au menu Paramètres."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez au menu Paramètres pour mettre à jour la navigation système"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Veille"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tous"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger la liste des commandes."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 26a4010..aebb52b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Votre profil professionnel est géré par <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Ce profil est connecté à <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, qui peut contrôler votre activité professionnelle sur le réseau, y compris l\'activité relative aux e-mails, aux applications et aux sites Web.\n\nVous êtes également connecté à <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, qui peut contrôler votre activité personnelle sur le réseau."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Maintenu déverrouillé par TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"L\'appareil restera verrouillé jusqu\'à ce que vous le déverrouilliez manuellement."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Recevoir les notifications plus vite"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Afficher les notifications avant de déverrouiller l\'appareil"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, merci"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Accédez rapidement à vos chats"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Les nouveaux chats <xliff:g id="APP_NAME">%1$s</xliff:g> s\'afficheront sous forme de bulles. Appuyez sur une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer.\n\nAppuyez sur la bulle"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Appuyez sur \"Gérer\" pour désactiver les bulles pour cette application"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigation système mise à jour. Pour apporter des modifications, accédez aux paramètres."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accédez aux paramètres pour mettre à jour la navigation système"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Mode Veille imminent"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tout"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossible de charger toutes les commandes."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index e1e8c76..7711742 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> xestiona o teu perfil de traballo, que está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>. Esta aplicación pode controlar a túa actividade na rede, mesmo os correos electrónicos, as aplicacións e os sitios web.\n\nTamén estás conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode controlar a túa actividade persoal na rede."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado por un axente de confianza"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado ata que o desbloquees manualmente"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Recibir notificacións máis rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Consúltaas antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Non, grazas"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover á parte infer. esquerda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover á parte inferior dereita"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter os chats á vista"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Os chats novos de <xliff:g id="APP_NAME">%1$s</xliff:g> mostraranse como burbullas. Toca unha para abrila ou arrástraa para movela.\n\nToca a burbulla"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Para desactivar as burbullas nesta aplicación, toca Xestionar"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Actualizouse a navegación do sistema. Para facer cambios, vai a Configuración."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Para actualizar a navegación do sistema, vai a Configuración"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Todo"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Non se puido cargar a lista de todos os controis."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outra"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index b16362b..cb09ac9 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"તમારી કાર્યાલયની પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ કરેલું છે, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent દ્વારા અનલૉક રાખેલું"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"વધુ ઝડપથી સૂચનાઓ મેળવો"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"તમે અનલૉક કરો તે પહેલાં તેમને જુઓ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ના, આભાર"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"નીચે ડાબે ખસેડો"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"નીચે જમણે ખસેડો"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"છોડી દો"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ચૅટને સૌથી પહેલાં રાખો"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ની નવી ચૅટ બબલ તરીકે દેખાશે. બબલને ખોલવા માટે તેને ટૅપ કરો. તેને ખસેડવા માટે ખેંચો.\n\nબબલને ટૅપ કરો"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"આ ઍપમાંથી બબલને બંધ કરવા માટે મેનેજ કરો પર ટૅપ કરો"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ઝડપી નિયંત્રણો"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"નિયંત્રણો ઉમેરો"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"જેમાંથી નિયંત્રણો ઉમેરવા હોય તે ઍપ પસંદ કરો"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> નિયંત્રણ ઉમેર્યું.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> નિયંત્રણો ઉમેર્યા.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"નિયંત્રણો"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"ઝડપી ઍક્સેસ માટેનાં નિયંત્રણો પસંદ કરો"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"મનપસંદ"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"તમામ"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"બધા નિયંત્રણોની સૂચિ લોડ કરી શકાઈ નથી."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"અન્ય"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3cb4c6f..4fd8310 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -92,7 +92,7 @@
     <string name="screenrecord_description" msgid="1123231719680353736">"रिकॉर्ड करते समय, Android सिस्टम आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली संवेदनशील जानकारी को कैप्चर कर सकता है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और ऑडियो शामिल हैं."</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडियो रिकॉर्ड करें"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिवाइस ऑडियो"</string>
-    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"आपके डिवाइस से आने वाली आवाज़. जैसे कि संगीत, कॉल, और रिंगटोन"</string>
+    <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"आपके डिवाइस से आने वाली आवाज़ जैसे कि संगीत, कॉल, और रिंगटोन"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"माइक्रोफ़ोन"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"डिवाइस ऑडियो और माइक्रोफ़ोन"</string>
     <string name="screenrecord_start" msgid="330991441575775004">"शुरू करें"</string>
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"आपकी वर्क प्रोफ़ाइल का प्रबंधन <xliff:g id="ORGANIZATION">%1$s</xliff:g> करता है. प्रोफ़ाइल <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> से कनेक्ट है, जो ईमेल, ऐप्लिकेशन और वेबसाइटों सहित आपकी नेटवर्क गतिविधि की निगरानी कर सकता है.\n\nआप <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> से भी कनेक्ट हैं, जो आपकी व्यक्तिगत नेटवर्क गतिविधि की निगरानी कर सकता है."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent की वजह से अनलॉक रखा गया है"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"जब तक कि आप मैन्‍युअल रूप से अनलॉक नहीं करते तब तक डिवाइस लॉक रहेगा"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"सूचनाएं ज़्यादा तेज़ी से पाएं"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"  उन्हें अनलॉक किए जाने से पहले देखें"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"रहने दें"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"बाईं ओर सबसे नीचे ले जाएं"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"सबसे नीचे दाईं ओर ले जाएं"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"खारिज करें"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"चैट को पहले से तैयार रखें"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> की नई चैट बबल्स की तरह दिखेंगी. इसे खोलने के लिए किसी बबल पर टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए, खींचें और छोड़ें.\n\nबबल पर टैप करें"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"इस ऐप्लिकेशन पर बबल्स को बंद करने के लिए \'प्रबंधित करें\' पर टैप करें"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेविगेशन अपडेट हो गया. बदलाव करने के लिए \'सेटिंग\' पर जाएं."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेविगेशन अपडेट करने के लिए \'सेटिंग\' में जाएं"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टैंडबाई"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"फटाफट नियंत्रण"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"कंट्राेल जोड़ें"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"वह ऐप्लिकेशन चुनें जिससे आप कंट्राेल जोड़ना चाहते हैं"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> कंट्रोल जोड़ा गया.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> कंट्रोल जोड़े गए.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"कंट्राेल"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"झटपट ऐक्सेस पाने के लिए कंट्राेल चुनें"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"पसंदीदा"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"सभी"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"सभी कंट्रोल की सूची लोड नहीं हो सकी."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d648aeb..bb53802 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Vašim radnim profilom upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan s aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> koja može nadzirati vaše poslovne aktivnosti na mreži, uključujući e-poruke, aplikacije i web-lokacije.\n\nPovezani ste i s aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> koja može nadzirati vaše osobne aktivnosti na mreži."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Otključano održava TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Uređaj će ostati zaključan dok ga ručno ne otključate"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Primajte obavijesti brže"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Pogledajte ih prije otključavanja"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -984,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premjesti u donji lijevi kut"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premjestite u donji desni kut"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Isticanje chatova"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi chatovi iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazat će se kao oblačići. Dodirnite oblačić da biste ga otvorili. Povucite da biste ga premjestili.\n\nDodirnite oblačić"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljanje da biste isključili oblačiće iz ove aplikacije"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ažurirana je navigacija sustavom. Možete je promijeniti u Postavkama."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Navigaciju sustavom možete ažurirati u Postavkama"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje mirovanja"</string>
@@ -1010,4 +1008,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Sve"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Popis svih kontrola nije se učitao."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 03151ae..7d1159c 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Munkaprofilját a(z) <xliff:g id="ORGANIZATION">%1$s</xliff:g> kezeli. A profil csatlakozik a(z) <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> alkalmazáshoz, amely figyelheti az Ön hálózati tevékenységeit, beleértve az e-maileket, alkalmazásokat és webhelyeket.\n\nCsatlakoztatta továbbá a(z) <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> alkalmazást, amely figyelheti az Ön személyes hálózati tevékenységeit."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Feloldva tartva TrustAgent által"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Az eszköz addig zárolva marad, amíg kézileg fel nem oldja"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Gyorsabban megkaphatja az értesítéseket"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Már a képernyőzár feloldása előtt megtekintheti őket"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nem, köszönöm"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Áthelyezés le és balra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Áthelyezés le és jobbra"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Elvetés"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"A csevegések előtérben tartása"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásból származó új csevegőüzenetek buborékként jelennek meg. A csevegés megnyitásához koppintson a buborékra. Az áthelyezéséhez húzza a buborékot a kívánt helyre.\n\nKoppintson a buborékra"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"A Kezelés gombra koppintva kapcsolhatja ki az alkalmazásból származó buborékokat"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A rendszer-navigáció módja megváltozott. Módosításához nyissa meg a Beállításokat."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"A rendszer-navigációs lehetőségeket a Beállításokban módosíthatja"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Készenléti mód"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Összes"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nem sikerült betölteni az összes vezérlő listáját."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Más"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index d8728f5..3f44736 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ձեր աշխատանքային պրոֆիլի կառավարիչն է <xliff:g id="ORGANIZATION">%1$s</xliff:g> կազմակերպությունը: Այն կապակցված է <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> հավելվածին, որը կարող է վերահսկել աշխատանքային ցանցում կատարած գործունեությունը, այդ թվում նաև էլփոստի հաշիվները, հավելվածները և կայքերը:\n\nԴուք կապակցված եք նաև <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> հավելվածին, որը կարող է վերահսկել անձնական ցանցում կատարած ձեր գործողությունները:"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ապակողպվում է TrustAgent-ի միջոցով"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Սարքը կմնա արգելափակված՝ մինչև ձեռքով չբացեք"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Ավելի արագ ստացեք ծանուցումները"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Տեսեք դրանք մինչև ապակողպելը"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ոչ"</string>
@@ -1001,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Բոլորը"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Չհաջողվեց բեռնել բոլոր կառավարների ցանկը։"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Այլ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 012a16e..18728a1 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Tetap terbuka kuncinya oleh TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Dapatkan pemberitahuan lebih cepat"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Lihat sebelum membuka kunci"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tidak"</string>
@@ -1001,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Semua"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Daftar semua kontrol tidak dapat dimuat."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lainnya"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 7542e3e..07b0d76 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Vinnusniðinu þínu er stýrt af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Sniðið er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Haldið opnu af TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Tækið verður læst þar til þú opnar það handvirkt"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Fáðu tilkynningar hraðar"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Sjáðu þær áður en þú opnar"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nei, takk"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Halda spjalli fyrir framan"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nýtt spjall úr <xliff:g id="APP_NAME">%1$s</xliff:g> birtist sem blöðrur. Ýttu á blöðru til að opna hana. Dragðu hana til að færa hana.\n\nÝttu á blöðruna"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ýttu á „Stjórna“ til að slökkva á blöðrum frá þessu forriti"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Kerfisstjórnun uppfærð. Þú getur breytt þessu í stillingunum."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Farðu í stillingar til að uppfæra kerfisstjórnun"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Biðstaða"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Allt"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Ekki tókst að hlaða lista yfir allar stýringar."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annað"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 65dc514..1c8bafd 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Il tuo profilo di lavoro è gestito da <xliff:g id="ORGANIZATION">%1$s</xliff:g> ed è collegato a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, da cui è possibile monitorare la tua attività di rete lavorativa, inclusi siti web, email e app.\n\nSei collegato anche a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, da cui è possibile monitorare la tua attività di rete personale."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Sbloccato da TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Il dispositivo resterà bloccato fino allo sblocco manuale"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Ricevi notifiche più velocemente"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Visualizza prima di sbloccare"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"No, grazie"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignora"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Tieni davanti le chat"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Le nuove chat da <xliff:g id="APP_NAME">%1$s</xliff:g> verranno visualizzate come bolle. Tocca una bolla per aprirla. Trascinala per spostarla.\n\nTocca la bolla"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tocca Gestisci per disattivare le bolle dall\'app"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigazione del sistema aggiornata. Per apportare modifiche, usa le Impostazioni."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Usa le Impostazioni per aggiornare la navigazione del sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tutti"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Impossibile caricare l\'elenco di tutti i controlli."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altro"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 2a9d596..a798cfa 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"פרופיל העבודה שלך מנוהל על ידי <xliff:g id="ORGANIZATION">%1$s</xliff:g>. הפרופיל מחובר לאפליקציה <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת, כולל הודעות אימייל, אפליקציות ואתרים.\n\nהפרופיל מחובר גם לאפליקציה <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, שיכולה לעקוב אחר הפעילות שלך ברשת."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"הנעילה נמנעת על ידי סביבה אמינה"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"המכשיר יישאר נעול עד שתבטל את נעילתו באופן ידני"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"קבלה מהירה של התראות"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"צפה בהן לפני שתבטל נעילה"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"לא, תודה"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"העברה לפינה השמאלית התחתונה"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"העברה לפינה הימנית התחתונה"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"סגירה"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"הצ\'אטים תמיד יוצגו מלפנים"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"צ\'אטים חדשים מאפליקציית <xliff:g id="APP_NAME">%1$s</xliff:g> יוצגו כבועות. יש להקיש על בועה כדי לפתוח אותה. יש לגרור אותה כדי להזיז אותה.\n\nיש להקיש על הבועה"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"יש להקיש על \'ניהול\' כדי להשבית את הבועות מהאפליקציה הזו"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"הכול"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"לא ניתן היה לטעון את הרשימה של כל הפקדים."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"אחר"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b4952ff..b62dae6 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"この仕事用プロファイルは<xliff:g id="ORGANIZATION">%1$s</xliff:g>によって管理され、<xliff:g id="APPLICATION_WORK">%2$s</xliff:g> に接続しています。このアプリはあなたの仕事のネットワーク アクティビティ(メール、アプリ、ウェブサイトなど)を管理できます。\n\nまた、<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> にも接続しているため、あなたの個人のネットワーク アクティビティも監視できます。"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"信頼エージェントがロック解除を管理"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"手動でロックを解除するまでロックされたままとなります"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"通知をすばやく確認できます"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ロックを解除する前にご確認ください"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"キャンセル"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"チャットを常に前面に表示"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> からの新しいチャットがバブルとして表示されます。バブルをタップするとチャットが表示されます。ドラッグすると移動します。\n\nバブルをタップしてください"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"すべて"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"全コントロールの一覧を読み込めませんでした。"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"その他"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 07b9e2a..8365673 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"თქვენს სამსახურის პროფილს მართავს <xliff:g id="ORGANIZATION">%1$s</xliff:g>. პროფილი დაკავშირებულია <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-თან, რომელსაც შეუძლია ქსელში თქვენი სამსახურეობრივი აქტივობის (მათ შორის, ელფოსტის, აპებისა და ვებსაიტების) მონიტორინგი.\n\nგარდა ამისა, თქვენ დაკავშირებული ხართ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-თან, რომელსაც ქსელში თქვენი პირადი აქტივობის მონიტორინგი შეუძლია."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"განბლოკილია TrustAgent-ის მიერ"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"მოწყობილობის დარჩება ჩაკეტილი, სანამ ხელით არ გახსნით"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"შეტყობინებების უფრო სწრაფად მიღება"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"იხილეთ განბლოკვამდე"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"არა, გმადლობთ"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ჩეთები წინ იყოს"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის ახალი ჩეთები ბუშტების სახით გამოჩნდება. გასახსნელად შეეხეთ ბუშტს. გადასატანად ჩაავლეთ.\n\nშეეხეთ ბუშტს"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ამ აპის ბუშტების გამოსართავად შეეხეთ „მართვას“"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"სისტემური ნავიგაცია განახლდა. ცვლილებების შესატანად გადადით პარამეტრებზე."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"სისტემური ნავიგაციის გასაახლებლად გადადით პარამეტრებზე"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"მოლოდინის რეჟიმი"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ყველა"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"მართვის ყველა საშუალების სია ვერ ჩაიტვირთა."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"სხვა"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index d6391891..e7ca415 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Жұмыс профиліңізді <xliff:g id="ORGANIZATION">%1$s</xliff:g> басқарады. Бұл профиль жұмыс желісіндегі белсенділігіңізді, соның ішінде электрондық хабарларды, қолданбаларды және веб-сайттарды бақылай алатын <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> қолданбасына қосылған.\n\nСондай-ақ сіз жеке желідегі белсенділігіңізді бақылай алатын <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> қолданбасына қосылғансыз."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent арқылы құлпы ашылды."</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Қолмен бекітпесін ашқанша құрылғы бекітілген күйде қалады"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Хабарландыруларды тезірек алу"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Бекітпесін ашу алдында оларды көру"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Жоқ, рақмет"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чаттарды жоғары жақтан көрсету"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасындағы жаңа чаттар қалқымалы анықтамалар түрінде шығады. Қалқымалы анықтаманы ашу үшін оны түртіңіз. Оны сүйреп жылжытыңыз.\n\nҚалқымалы анықтаманы түртіңіз."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқымалы анықтамаларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Жүйе навигациясы жаңартылды. Өзгерту енгізу үшін \"Параметрлер\" бөліміне өтіңіз."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Жүйе навигациясын жаңарту үшін \"Параметрлер\" бөліміне өтіңіз."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Күту режимі"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Барлығы"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Барлық басқару элементі тізімі жүктелмеді."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Басқа"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 8306dff..d8d300f 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"កម្រងព័ត៌មាន​ការងារ​របស់អ្នក​ស្ថិតក្រោម​គ្រប់គ្រង​របស់ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ។ កម្រង​ព័ត៌មាននេះ​ត្រូវបាន​ភ្ជាប់​ទៅ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ដែលអាច​តាមដាន​សកម្មភាព​បណ្តាញ​របស់អ្នក រួមទាំង​អ៊ីមែល កម្មវិធី និង​គេហទំព័រ​ផងដែរ។\n\nអ្នកក៏ត្រូវបាន​ភ្ជាប់​ទៅ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ដែលអាច​តាមដាន​សកម្មភាព​បណ្តាញ​ផ្ទាល់ខ្លួន​របស់​អ្នក។"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"បាន​ដោះសោ​ដោយភ្នាក់ងារ​​ទុកចិត្ត"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ឧបករណ៍​នឹង​ចាក់​សោ​រហូត​ដល់​អ្នក​ដោះ​សោ​ដោយ​ដៃ"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ទទួល​បាន​ការ​ជូន​ដំណឹង​កាន់តែ​លឿន"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ឃើញ​ពួកវា​មុន​ពេល​ដោះ​សោ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ទេ អរគុណ!"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង​"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោម​ខាងស្ដាំ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"រក្សាទុកការជជែក​នៅផ្នែក​ខាងមុខ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"ការជជែកថ្មីៗពី <xliff:g id="APP_NAME">%1$s</xliff:g> នឹងបង្ហាញ​ជាសារលេចឡើង។ ចុច​សារលេច​ឡើង ដើម្បី​បើកវា។ អូស​ដើម្បីផ្លាស់ទី​សារលេចឡើងនេះ។\n\nចុចសារ​លេចឡើងនេះ"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ចុច \"គ្រប់គ្រង\" ដើម្បីបិទ​សារលេចឡើង​ពីកម្មវិធីនេះ"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"បានធ្វើ​បច្ចុប្បន្នភាព​ការរុករកក្នុង​ប្រព័ន្ធ។ ដើម្បីធ្វើការផ្លាស់ប្ដូរ សូមចូលទៅ​កាន់ការកំណត់។"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ចូល​ទៅកាន់​ការកំណត់ ដើម្បី​ធ្វើបច្ចុប្បន្នភាព​ការរុករក​ក្នុង​ប្រព័ន្ធ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ផ្អាក​ដំណើរការ"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ទាំងអស់"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"មិនអាច​ផ្ទុក​បញ្ជី​នៃការគ្រប់គ្រង​ទាំងអស់​បានទេ។"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ផ្សេងៗ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 880e083..0165b08 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಅನ್ನು <xliff:g id="ORGANIZATION">%1$s</xliff:g> ನಿರ್ವಹಿಸುತ್ತಿದೆ. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ಗೆ ಪ್ರೊಫೈಲ್ ಸಂಪರ್ಕಗೊಂಡಿರುವ ಕಾರಣ, ಅದು ನಿಮ್ಮ ಇಮೇಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‌ಗಳೂ ಸೇರಿದಂತೆ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು.\n\nನೀವು <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ಗೆ ಕೂಡಾ ಸಂಪರ್ಕಗೊಂಡಿದ್ದೀರಿ, ಇದು ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ನೆಟ್‌ವರ್ಕ್ ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ಮಾಡಬಹುದು."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ನಿಂದ ಅನ್‌ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ನೀವಾಗಿಯೇ ಅನ್‌ಲಾಕ್‌ ಮಾಡುವವರೆಗೆ ಸಾಧನವು ಲಾಕ್‌ ಆಗಿಯೇ ಇರುತ್ತದೆ"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ವೇಗವಾಗಿ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ನೀವು ಅನ್‌ಲಾಕ್‌ ಮಾಡುವ ಮೊದಲೇ ಅವುಗಳನ್ನು ನೋಡಿ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ಧನ್ಯವಾದಗಳು"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ಸ್ಕ್ರೀನ್‌ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ವಜಾಗೊಳಿಸಿ"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ಚಾಟ್‌ಗಳನ್ನು ಮುಂಚೂಣಿಯಲ್ಲಿಡಿ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ನಿಂದ ಹೊಸ ಚಾಟ್‌ಗಳು ಬಬಲ್‌ಗಳಾಗಿ ಕಾಣಿಸುತ್ತದೆ. ಅದನ್ನು ತೆರೆಯಲು ಬಬಲ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಸರಿಸಲು ಡ್ರ್ಯಾಗ್ ಮಾಡಿ.\n\nಬಬಲ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ಈ ಆ್ಯಪ್‌ನಿಂದ ಬಬಲ್‌ಗಳನ್ನು ಆಫ್ ಮಾಡಲು ನಿರ್ವಹಿಸಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್‌ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್‌ಬೈ"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ತ್ವರಿತ ನಿಯಂತ್ರಣಗಳು"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಿ"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲು ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ನಿಯಂತ್ರಣಗಳನ್ನು ಸೇರಿಸಲಾಗಿದೆ.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"ನಿಯಂತ್ರಣಗಳು"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"ತ್ವರಿತ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಯಂತ್ರಣಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ಮೆಚ್ಚಿನವುಗಳು"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ಎಲ್ಲಾ"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"ಎಲ್ಲಾ ನಿಯಂತ್ರಣಗಳ ಪಟ್ಟಿಯನ್ನು ಲೋಡ್ ಮಾಡಲು ಆಗಲಿಲ್ಲ."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ಇತರ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ca8cdb0..64f5ff8 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이 프로필은 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n개인 네트워크 활동을 모니터링할 수 있는 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에도 연결됩니다."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent가 잠금 해제함"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"알림을 더욱 빠르게 받기"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"잠금 해제하기 전에 알림을 봅니다."</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"사용 안함"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"채팅을 항상 상단에 표시"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 새로운 채팅이 버블로 표시됩니다. 버블을 열려면 탭하세요. 버블을 이동하려면 드래그하세요.\n\n버블을 탭하세요."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 버블을 사용 중지하려면 관리를 탭하세요."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"시스템 탐색이 업데이트되었습니다. 변경하려면 설정으로 이동하세요."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"설정으로 이동하여 시스템 탐색을 업데이트하세요."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"대기"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"전체"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"전체 컨트롤 목록을 로드할 수 없습니다."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"기타"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 719380e..00d6699 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Жумуш профилиңизди <xliff:g id="ORGANIZATION">%1$s</xliff:g> башкарат. Ал электрондук почта, колдонмолор жана вебсайттар сыяктуу жумуш тармагыңыздагы аракеттерди көзөмөлдөй турган <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> колдонмосуна туташкан.\n\nМындан тышкары, тармактагы жеке аракеттериңизди көзөмөлдөгөн <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> колдонмосуна туташып турасыз."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ишеним агенти кулпусун ачты"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Түзмөктүн кулпусу кол менен ачылмайынча кулпуланган бойдон алат"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Эскертмелерди тезирээк алуу"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Аларды кулпудан чыгараардан мурун көрүңүз"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Жок, рахмат"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төмөнкү сол жакка жылдыруу"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төмөнкү оң жакка жылдырыңыз"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Маектерди ар дайым көрүп туруңуз"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жаңы маектер калкып чыкма билдирмелер түрүндө көрүнөт. Аны ачуу үчүн калкып чыкма билдирмени таптап коюңуз. Аны сүйрөп жылдырыңыз.\n\nКалкып чыкма билдирмени таптап коюңуз"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бул колдонмодогу калкып чыкма билдирмелерди өчүрүү үчүн \"Башкарууну\" басыңыз"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Тутум чабыттоосу жаңырды. Өзгөртүү үчүн, Жөндөөлөргө өтүңүз."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Тутум чабыттоосун жаңыртуу үчүн Жөндөөлөргө өтүңүз"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Көшүү режими"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Баары"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Бардык көзөмөлдөрдүн тизмеси жүктөлгөн жок."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Башка"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 1737e0c..c937001 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານແມ່ນຖືກຈັດການໂດຍ <xliff:g id="ORGANIZATION">%1$s</xliff:g>. ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກດັ່ງກ່າວເຊື່ອມຕໍ່ຫາ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍຂອງທ່ານ, ຮວມທັງອີເມວ, ແອັບ ແລະ ເວັບໄຊໄດ້.\n\nນອກຈາກນັ້ນ, ທ່ານຍັງເຊື່ອມຕໍ່ຫາ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ເຊິ່ງສາມາດຕິດຕາມການເຄື່ອນໄຫວເຄືອຂ່າຍສ່ວນຕົວຂອງທ່ານໄດ້."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ປັອດລັອກປະໄວ້ໂດຍ TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Device will stay locked until you manually unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ຮັບເອົາການ​ແຈ້ງເຕືອນ​ໄວຂຶ້ນ"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ເບິ່ງພວກ​ມັນກ່ອນ​ທ່ານຈະ​ປົດລັອກ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ບໍ່, ຂອບໃຈ"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ສະແດງການສົນທະນາໄວ້ໜ້າສະເໝີ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"ການສົນທະນາໃໝ່ຈາກ <xliff:g id="APP_NAME">%1$s</xliff:g> ຈະປາກົດເປັນ bubble. ແຕະໃສ່ bubble ເພື່ອເປີດມັນ ລາກເພື່ອເປີດມັນ.\n\nແຕະໃສ່ bubble"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ແຕະຈັດການເພື່ອປິດ bubble ຈາກແອັບນີ້"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ອັບເດດການນຳທາງລະບົບແລ້ວ. ເພື່ອປ່ຽນແປງ, ກະລຸນາໄປທີ່ການຕັ້ງຄ່າ."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ໄປທີ່ການຕັ້ງຄ່າເພື່ອອັບເດດການນຳທາງລະບົບ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ສະແຕນບາຍ"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ທັງໝົດ"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"ບໍ່ສາມາດໂຫຼດລາຍຊື່ການຄວບຄຸມທັງໝົດໄດ້."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ອື່ນໆ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 31fd57f..d498878 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jūsų darbo profilį tvarko „<xliff:g id="ORGANIZATION">%1$s</xliff:g>“. Profilis susietas su programa „<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>“, kuri gali stebėti jūsų tinklo veiklą, įskaitant el. laiškus, programas ir svetaines.\n\nTaip pat esate prisijungę prie programos „<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>“, kuri gali stebėti asmeninio tinklo veiklą."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Atrakinta taikant „TrustAgent“"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Įrenginys liks užrakintas, kol neatrakinsite jo neautomatiniu būdu"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Greičiau gaukite pranešimus"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Peržiūrėti prieš atrakinant"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, ačiū"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Rodyti pokalbius priekyje"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nauji pokalbiai iš programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ bus rodomi kaip debesėliai. Palieskite debesėlį, kad jį atidarytumėte. Nuvilkite, kad perkeltumėte.\n\nPalieskite debesėlį"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Palieskite „Tvarkyti“, kad išjungtumėte debesėlius šioje programoje"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemos naršymo funkcijos atnaujintos. Jei norite pakeisti, eikite į skiltį „Nustatymai“."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Eikite į skiltį „Nustatymai“, kad atnaujintumėte sistemos naršymo funkcijas"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Budėjimo laikas"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Visi"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nepavyko įkelti visų valdiklių sąrašo."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Kita"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 44e15cc..a25ae2a 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jūsu darba profilu pārvalda <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profils ir saistīts ar lietotni <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, kura var pārraudzīt jūsu tīklā veiktās darbības, tostarp saņemtos un nosūtītos e-pasta ziņojumus, instalētās lietotnes un apmeklētās tīmekļa vietnes.\n\nIr izveidots savienojums ar lietotni <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, kas var pārraudzīt jūsu tīklā veiktās privātās darbības, tostarp saņemtos un nosūtītos e-pasta ziņojumus, instalētās lietotnes un apmeklētās tīmekļa vietnes."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Bloķēšanu liedzis TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Ierīce būs bloķēta, līdz to manuāli atbloķēsiet."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Saņemiet paziņojumus ātrāk"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Skatiet tos pirms atbloķēšanas."</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nē"</string>
@@ -984,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pārvietot apakšpusē pa kreisi"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pārvietot apakšpusē pa labi"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Nerādīt"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Sarunas priekšplānā"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Jaunas sarunas no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> tiks parādītas kā burbuļi. Pieskarieties kādam burbulim, lai to atvērtu. Velciet, lai to pārvietotu.\n\nPieskarieties burbulim."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Pieskarieties pogai “Pārvaldīt”, lai izslēgtu burbuļus no šīs lietotnes."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistēmas navigācija ir atjaunināta. Lai veiktu izmaiņas, atveriet iestatījumus."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Atveriet iestatījumus, lai atjauninātu sistēmas navigāciju"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Gaidstāve"</string>
@@ -1010,4 +1008,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Visas"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nevarēja ielādēt sarakstu ar visām vadīklām."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Cita"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2e6f6f5..47b0558 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ മാനേജുചെയ്യുന്നത്. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ആപ്പിലേക്ക് പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും.\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ആപ്പിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ വ്യക്തിഗത നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ഉപയോഗിച്ച് അൺലോക്ക് ചെയ്‌തത്"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"നിങ്ങൾ സ്വമേധയാ അൺലോക്കുചെയ്യുന്നതുവരെ ഉപകരണം ലോക്കുചെയ്‌തതായി തുടരും"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"അറിയിപ്പുകൾ വേഗത്തിൽ സ്വീകരിക്കുക"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"അൺലോക്കുചെയ്യുന്നതിന് മുമ്പ് അവ കാണുക"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"വേണ്ട, നന്ദി"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്‌മിസ് ചെയ്യുക"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ചാറ്റുകൾ ഏറ്റവും ആദ്യം കാണുന്ന രീതിയിൽ വയ്ക്കുക"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള പുതിയ ചാറ്റുകൾ ബബിളുകളായി ദൃശ്യമാവും. ഇത് തുറക്കാൻ ബബിൾ ടാപ്പ് ചെയ്യുക. ഇത് നീക്കാൻ വലിച്ചിടുക.\n\nബബിൾ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ഈ ആപ്പിൽ നിന്നുള്ള ബബിളുകൾ ഓഫാക്കാൻ \'മാനേജ് ചെയ്യുക\' ടാപ്പ് ചെയ്യുക"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്‌തു. മാറ്റങ്ങൾ വരുത്താൻ ക്രമീകരണത്തിലേക്ക് പോവുക."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"സിസ്‌റ്റം നാവിഗേഷൻ അപ്‌ഡേറ്റ് ചെയ്യാൻ ക്രമീകരണത്തിലേക്ക് പോവുക"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"സ്‌റ്റാൻഡ്‌ബൈ"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ദ്രുത നിയന്ത്രണങ്ങൾ"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"നിയന്ത്രണങ്ങൾ ചേർക്കുക"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"നിയന്ത്രണങ്ങൾ ചേർക്കാൻ ഒരു ആപ്പ് തിരഞ്ഞെടുക്കുക"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> നിയന്ത്രണങ്ങൾ ചേർത്തു.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> നിയന്ത്രണം ചേർത്തു.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"നിയന്ത്രണങ്ങൾ"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"അതിവേഗ ആക്‌സസിനുള്ള നിയന്ത്രണങ്ങൾ തിരഞ്ഞെടുക്കുക"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"പ്രിയപ്പെട്ടവ"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"എല്ലാം"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"എല്ലാ നിയന്ത്രണങ്ങളുടെയും ലിസ്റ്റ് ലോഡ് ചെയ്യാനായില്ല."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"മറ്റുള്ളവ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index ea93816..247a81d 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Таны ажлын профайлыг <xliff:g id="ORGANIZATION">%1$s</xliff:g> удирддаг. Энэ нь таны имэйл, апп, вэб хуудас зэрэг сүлжээний үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>-тай холбогдсон. \n\nМөн таны сүлжээний хувийн үйл ажиллагааг хянах боломжтой <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>-д холбогдсон байна."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent-р түгжээгүй байлгасан"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Таныг гараар нээх хүртэл төхөөрөмж түгжээтэй байх болно"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Мэдэгдлийг хурдан авах"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Түгжээг тайлахын өмнө үзнэ үү"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Үгүй"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Зүүн доош зөөх"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Баруун доош зөөх"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Үл хэрэгсэх"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чатуудыг дэлгэцийн дээд талд байлгах"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н шинэ чатууд нь бөмбөлөг маягаар харагдана. Бөмбөлгийг нээхийн тулд түүнийг товшино уу. Түүнийг зөөхийн тулд чирнэ үү.\n\nБөмбөлгийг товшино уу"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Энэ аппын бөмбөлгүүдийг унтраахын тулд Удирдах дээр товшино уу"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Системийн навигацыг шинэчиллээ. Өөрчлөхийн тулд Тохиргоо руу очно уу."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Системийн навигацыг шинэчлэхийн тулд Тохиргоо руу очно уу"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Зогсолтын горим"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Бүх"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Бүх хяналтын жагсаалтыг ачаалж чадсангүй."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Бусад"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3c7e18e..118627a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते. प्रोफाइल <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nतुम्ही <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शीदेखील कनेक्‍ट केले आहे, जे आपल्या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ने अनलॉक ठेवले"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"तुम्ही मॅन्युअली अनलॉक करेपर्यंत डिव्हाइस लॉक राहील"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"सूचना अधिक जलद मिळवा"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"तुम्ही अनलॉक करण्‍यापूर्वी त्यांना पहा"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"नाही, नको"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"डिसमिस करा"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"चॅट दिसतील असे ठेवा"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> वरील नवीन चॅट बुडबुडे म्हणून दिसतील. बुडबुडे उघडण्यासाठी त्यावर टॅप करा. तो हलवण्यासाठी ड्रॅग करा.\n\nबुडबुड्यावर टॅप करा"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"या अ‍ॅपमधून बुडबुडे बंद करण्यासाठी व्यवस्थापित करा वर टॅप करा"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"सिस्टम नेव्हिगेशन अपडेट केले. बदल करण्यासाठी, सेटिंग्जवर जा."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"सिस्टम नेव्हिगेशन अपडेट करण्यासाठी सेटिंग्जवर जा"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्टँडबाय"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"क्विक नियंत्रणे"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"नियंत्रणे जोडा"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"ज्यामधून नियंत्रणे जोडायची आहेत ते ॲप निवडा"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> नियंत्रणे जोडली.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> नियंत्रण जोडले.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"नियंत्रणे"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"झटपट अ‍ॅक्सेससाठी नियंत्रणे निवडा"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"आवडते"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"सर्व"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"सर्व नियंत्रणांची सूची लोड करता आली नाही."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"इतर"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 6d266737..454ebfb 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil itu dihubungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut dihubungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Dibiarkan tidak berkunci oleh TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Dapatkan pemberitahuan lebih cepat"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Lihat sebelum anda membuka kunci"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Tidak"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Alihkan ke bawah sebelah kiri"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Alihkan ke bawah sebelah kanan"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ketepikan"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Pastikan sembang sentiasa di hadapan"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Sembang baharu daripada <xliff:g id="APP_NAME">%1$s</xliff:g> akan dipaparkan sebagai gelembung. Ketik gelembung untuk membuka. Seret untuk mengalihkan gelembung.\n\nKetik gelembung itu"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Ketik Urus untuk mematikan gelembung daripada apl ini"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigasi sistem dikemas kini. Untuk membuat perubahan, pergi ke Tetapan."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pergi ke Tetapan untuk mengemas kini navigasi sistem"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tunggu sedia"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Semua"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Senarai semua kawalan tidak dapat dimuatkan."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Lain-lain"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index dd3e6c1..c65f949 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"သင်၏ အလုပ်ပရိုဖိုင်ကို <xliff:g id="ORGANIZATION">%1$s</xliff:g> က စီမံခန့်ခွဲထားသည်။ ပရိုဖိုင်သည် အီးမေး၊ အက်ပ်နှင့် ဝဘ်ဆိုက်များအပါအဝင် သင်၏ကွန်ရက် လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> သို့ ချိတ်ဆက်ထားပါသည်။\n\nသင်၏ ကိုယ်ရေးကိုယ်တာ ကွန်ရက်လုပ်ဆောင်ချက်များကို စောင့်ကြည့်နိုင်သည့် <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> သို့လည်း ချိတ်ဆက်ထားပါသည်။"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ဖြင့် ဆက်ဖွင့်ထားရန်"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"သင်က လက်ဖြင့် သော့မဖွင့်မချင်း ကိရိယာမှာ သော့ပိတ်လျက် ရှိနေမည်"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"အကြောင်းကြားချက်များ မြန်မြန်ရရန်"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"မဖွင့်ခင် ၎င်းတို့ကို ကြည့်ပါ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"မလိုအပ်ပါ"</string>
@@ -1001,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"အားလုံး"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"ထိန်းချုပ်မှုအားလုံး၏ စာရင်းကို ဖွင့်၍မရပါ။"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"အခြား"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5743215..d8f6294 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-poster, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Holdes opplåst med TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheten forblir låst til du låser den opp manuelt"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Motta varsler raskere"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Se dem før du låser opp"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nei takk"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Ha chatter i forgrunnen"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nye chatter fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som bobler. Trykk på en boble for å åpne den. Dra for å flytte den.\n\nTrykk på boblen"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen er oppdatert. For å gjøre endringer, gå til Innstillinger."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Gå til Innstillinger for å oppdatere systemnavigeringen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ventemodus"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listen over alle kontroller kunne ikke lastes inn."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Annet"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index ef80cdc..73564a1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ले तपाईंको कार्य प्रोफाइलको व्यवस्थापन गर्छ। उक्त प्रोफाइल तपाईंका इमेल, अनुप्रयोग र वेवसाइटहरू लगायत तपाईंको नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> मा जडान छ। \n\nतपाईं आफ्नो व्यक्तिगत नेटवर्कको गतिविधिको अनुगमन गर्नसक्ने <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> मा पनि जडान हुनुहुन्छ।"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ले खुला राखेको"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"तपाईँले अनलक गर्नअघि तिनीहरूलाई हेर्नुहोस्"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"धन्यवाद पर्दैन"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"कुराकानीलाई अग्रभूमिमा राख्नुहोस्"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> का नयाँ कुराकानीहरू बबलका रूपमा देखा पर्ने छन्। बबल खोल्न त्यसमा ट्याप गर्नुहोस्। बबल सार्न त्यसलाई घिसार्नुहोस्।\n\nबबलमा ट्याप गर्नुहोस्"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"यो अनुप्रयोगमा बबल निष्क्रिय पार्न व्यवस्थापन गर्नुहोस् नामक बटन ट्याप गर्नुहोस्"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"प्रणालीको नेभिगेसन अद्यावधिक गरियो। परिवर्तन गर्न सेटिङमा जानुहोस्।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"प्रणालीको नेभिगेसन अद्यावधिक गर्न सेटिङमा जानुहोस्"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"स्ट्यान्डबाई"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"द्रुत नियन्त्रणहरू"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"नियन्त्रणहरू थप्नुहोस्"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"नियन्त्रणहरू जुन अनुप्रयोगबाट थप्ने हो त्यो अनुप्रयोग छनौट गर्नुहोस्"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> वटा नियन्त्र थपियो।</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> नियन्त्र थपियो</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"नियन्त्रणहरू"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"द्रुत पहुँचका लागि नियन्त्रणहरू छनौट गर्नुहोस्"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"मन पर्ने कुराहरू"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"सबै"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"सबै नियन्त्रणहरूको सूची लोड गर्न सकिएन।"</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"अन्य"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index ae9b829..86f0f8f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Het profiel is verbonden met <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, waarmee je werkgerelateerde netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden.\n\nJe bent ook verbonden met <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, waarmee je persoonlijke netwerkactiviteit kan worden bijgehouden."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Ontgrendeld gehouden door TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Het apparaat blijft vergrendeld totdat u het handmatig ontgrendelt"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Sneller meldingen ontvangen"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Weergeven voordat u ontgrendelt"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nee, bedankt"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Naar linksonder verplaatsen"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Naar rechtsonder verplaatsen"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Sluiten"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chats op de voorgrond houden"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nieuwe chats van <xliff:g id="APP_NAME">%1$s</xliff:g> worden weergegeven als bubbels. Tik op een bubbel om deze te openen. Sleep om deze te verplaatsen.\n\nTik op de bubbel"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tik op Beheren om bubbels van deze app uit te schakelen"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systeemnavigatie geüpdatet. Als je wijzigingen wilt aanbrengen, ga je naar Instellingen."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ga naar Instellingen om de systeemnavigatie te updaten"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stand-by"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Alle"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Kan lijst met alle bedieningselementen niet laden."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Overig"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 9aad495..f46036e 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ଦ୍ୱାରା ପରିଚାଳନା କରାଯାଉଛି। ପ୍ରୋଫାଇଲଟି <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ସହ ସଂଯୁକ୍ତ ଅଛି, ଯାହା ଇମେଲ୍‍, ଆପ୍‌ ଓ ୱେବସାଇଟ୍‍ ସମେତ ଆପଣଙ୍କ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।\n\nଆପଣ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>ରେ ମଧ୍ୟ ସଂଯୁକ୍ତ, ଯାହା ଆପଣଙ୍କ ବ୍ୟକ୍ତିଗତ ନେଟୱର୍କ ଗତିବିଧିକୁ ନିରୀକ୍ଷଣ କରିପାରେ।"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ଦ୍ୱାରା ଅନ୍‌ଲକ୍ ରହିଛି"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ଯେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଆପଣ ମାନୁଆଲୀ ଅନଲକ୍‌ କରିନାହାନ୍ତି, ସେତେବେଳ ପର୍ଯ୍ୟନ୍ତ ଡିଭାଇସ୍‌ ଲକ୍‌ ରହିବ"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ବିଜ୍ଞପ୍ତିକୁ ଶୀଘ୍ର ପ୍ରାପ୍ତ କରନ୍ତୁ"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ଅନଲକ୍‌ କରିବା ପୁର୍ବରୁ ସେମାନଙ୍କୁ ଦେଖନ୍ତୁ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ନାହିଁ, ଥାଉ"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ଖାରଜ କରନ୍ତୁ"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ଚାଟଗୁଡ଼ିକ ଆଗ ପଟେ ରଖନ୍ତୁ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର ନୂଆ ଚାଟଗୁଡ଼ିକ ବବଲ୍‍ ଭାବରେ ଦେଖାଯିବ। ଏହାକୁ ଖୋଲିବା ପାଇଁ ଏକ ବବଲରେ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବା ପାଇଁ ଟାଣନ୍ତୁ। \n\nବବଲରେ ଟାପ୍ କରନ୍ତୁ"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ଏହି ଆପର ବବଲଗୁଡ଼ିକ ବନ୍ଦ କରିବା ପାଇଁ \'ପରିଚାଳନା କରନ୍ତୁ\' ବଟନରେ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ ହୋଇଛି। ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, ସେଟିଂସ୍‌କୁ ଯାଆନ୍ତୁ।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ଅପ୍‌ଡେଟ୍ କରିବା ପାଇଁ ସେଟିଂସ୍‍କୁ ଯାଆନ୍ତୁ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ଷ୍ଟାଣ୍ଡବାଏ"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ଦ୍ରୁତ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"କେଉଁ ଆପରୁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ ଯୋଗ କରିବେ ତାହା ଚୟନ କରନ୍ତୁ"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g>ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g>ଟି ନିୟନ୍ତ୍ରଣ ଯୋଗ କରାଯାଇଛି।</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"ଶୀଘ୍ର ଆକ୍ସେସ୍ ପାଇଁ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକୁ ଚୟନ କରନ୍ତୁ"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ପସନ୍ଦଗୁଡ଼ିକ"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ସବୁ"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"ସବୁ ନିୟନ୍ତ୍ରଣର ତାଲିକା ଲୋଡ୍ କରିପାରିଲା ନାହିଁ।"</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ଅନ୍ୟ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index cbd278e..3a43f0f 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਪ੍ਰੋਫਾਈਲ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਕਾਰਜ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ਟਰੱਸਟ-ਏਜੰਟ ਵੱਲੋਂ ਅਣਲਾਕ ਰੱਖਿਆ ਗਿਆ"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ਡੀਵਾਈਸ ਲਾਕ ਰਹੇਗਾ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਣਲਾਕ ਨਹੀਂ ਕਰਦੇ"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ਅਣਲਾਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਉਹਨਾਂ ਨੂੰ ਦੇਖੋ"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"ਚੈਟਾਂ ਨੂੰ ਪਹਿਲਾਂ ਤੋਂ ਤਿਆਰ ਰੱਖੋ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀਆਂ ਨਵੀਆਂ ਚੈਟਾਂ ਬੁਲਬੁਲਿਆਂ ਵਾਂਗ ਦਿਸਣਗੀਆਂ। ਇਸ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਕਿਸੇ ਬੁਲਬੁਲੇ \'ਤੇ ਟੈਪ ਕਰੋ। ਇਸ ਨੂੰ ਇੱਕ ਥਾਂ ਤੋਂ ਦੂਜੀ ਥਾਂ \'ਤੇ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।\n\nਬੁਲਬੁਲੇ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ਇਸ ਐਪ \'ਤੇ ਬੁਲਬੁਲੇ ਬੰਦ ਕਰਨ ਲਈ \'ਪ੍ਰਬੰਧਨ ਕਰੋ\' \'ਤੇ ਟੈਪ ਕਰੋ"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਅੱਪਡੇਟ ਹੋ ਗਿਆ। ਤਬਦੀਲੀਆਂ ਕਰਨ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ।"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ਸਿਸਟਮ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ਸਟੈਂਡਬਾਈ"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"ਤਤਕਾਲ ਕੰਟਰੋਲ"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"ਉਹ ਐਪ ਚੁਣੋ ਜਿੱਥੋਂ ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕਰਨੇ ਹਨ"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="one"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ।</item>
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> ਕੰਟਰੋਲ ਸ਼ਾਮਲ ਕੀਤੇ ਗਏ।</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"ਕੰਟਰੋਲ"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"ਤਤਕਾਲ ਪਹੁੰਚ ਲਈ ਕੰਟਰੋਲ ਚੁਣੋ"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ਮਨਪਸੰਦ"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ਸਭ"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"ਸਾਰੇ ਕੰਟਰੋਲਾਂ ਦੀ ਸੂਚੀ ਨੂੰ ਲੋਡ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ।"</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ਹੋਰ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index ad54bc9..1bbe80a 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Organizacja <xliff:g id="ORGANIZATION">%1$s</xliff:g> zarządza Twoim profilem do pracy. Profil jest połączony z aplikacją <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, która może monitorować Twoją aktywność w sieci, w tym e-maile, aplikacje i strony internetowe.\n\nMasz też połączenie z aplikacją <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, która może monitorować Twoją osobistą aktywność w sieci."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Blokada anulowana przez agenta zaufania"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Urządzenie pozostanie zablokowane, aż odblokujesz je ręcznie"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Szybszy dostęp do powiadomień"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Zobacz powiadomienia, jeszcze zanim odblokujesz ekran"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nie, dziękuję"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Przenieś w lewy dolny róg"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Przenieś w prawy dolny róg"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zamknij"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Wyświetlaj czaty na wierzchu"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nowe czaty z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> będą pojawiać się jako dymki. Kliknij dymek, aby go otworzyć. Przeciągnij dymek, jeśli chcesz go przenieść.\n\nKliknij dymek"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Kliknij Zarządzaj, aby wyłączyć dymki z tej aplikacji"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Nawigacja w systemie została zaktualizowana. Aby wprowadzić zmiany, otwórz Ustawienia."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Otwórz Ustawienia, by zaktualizować nawigację w systemie"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Tryb gotowości"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Wszystko"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Nie udało się wczytać listy elementów sterujących."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Inne"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 300461d..61ac664 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal de rede."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter chats em primeiro plano"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novos chats do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecerão como balões. Toque em um balão para abrir o chat. Arraste para mover.\n\nToque no balão"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9d7fb35..199da15 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"O seu perfil de trabalho é gerido pela <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está associado à aplicação <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorizar a atividade da rede de trabalho, incluindo emails, aplicações e Sites.\n\nTambém está associado à aplicação <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorizar a atividade da rede pessoal."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mantido desbloqueado pelo TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até ser desbloqueado manualmente"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Receber notificações mais rapidamente"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ver antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover p/ parte infer. esquerda"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover parte inferior direita"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mantenha os chats em primeiro plano"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Os novos chats da app <xliff:g id="APP_NAME">%1$s</xliff:g> serão apresentados como balões. Toque num balão para o abrir. Arraste para o mover.\n\nToque no balão."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em Gerir para desativar os balões desta app."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"A navegação no sistema foi atualizada. Para efetuar alterações, aceda às Definições."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Aceda às Definições para atualizar a navegação no sistema."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Modo de espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tudo"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista dos controlos."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 300461d..61ac664 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Seu perfil de trabalho é gerenciado por <xliff:g id="ORGANIZATION">%1$s</xliff:g>. O perfil está conectado a <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, que pode monitorar sua atividade profissional de rede, incluindo e-mails, apps e websites.\n\nVocê também está conectado a <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, que pode monitorar sua atividade pessoal de rede."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Desbloqueado pelo TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"O dispositivo permanecerá bloqueado até que você o desbloqueie manualmente"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Receba notificações mais rápido"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Veja-as antes de desbloquear"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Não, obrigado"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Manter chats em primeiro plano"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novos chats do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecerão como balões. Toque em um balão para abrir o chat. Arraste para mover.\n\nToque no balão"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toque em \"Gerenciar\" para desativar os balões desse app"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navegação no sistema atualizada. Se quiser alterá-la, acesse as configurações."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Acesse as configurações para atualizar a navegação no sistema"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Em espera"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Todos"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Não foi possível carregar a lista de controles."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Outro"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 845714e..e72f68c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profilul de serviciu este gestionat de <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilul este conectat la <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua de serviciu, inclusiv e-mailurile, aplicațiile și site-urile accesate.\n\nDe asemenea, v-ați conectat la <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, care vă poate monitoriza activitatea în rețeaua personală."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Deblocat de TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Dispozitivul va rămâne blocat până când îl deblocați manual"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Obțineți notificări mai rapid"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Doresc să se afișeze înainte de deblocare"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nu, mulț."</string>
@@ -984,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mutați în stânga jos"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mutați în dreapta jos"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Închideți"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mențineți conversațiile prin chat în prim-plan"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Conversațiile noi prin chat din <xliff:g id="APP_NAME">%1$s</xliff:g> vor apărea sub forma unor baloane. Atingeți un balon pentru a deschide o conversație. Trageți-l pentru a-l muta.\n\nAtingeți balonul."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigarea în sistem a fost actualizată. Pentru a face modificări, accesați Setările."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Accesați Setările pentru a actualiza navigarea în sistem"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
@@ -1010,4 +1008,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Toate"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista cu toate comenzile nu a putut fi încărcată."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index c32627d..85b1bb3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Вашим рабочим профилем управляет организация \"<xliff:g id="ORGANIZATION">%1$s</xliff:g>\". Приложение \"<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>\" может отслеживать ваши действия в корпоративной сети, включая работу с электронной почтой, приложениями и веб-сайтами.\n\nТакже запущено приложение \"<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>\", которое может отслеживать ваши действия в сети, выполняемые в личном профиле."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Разблокировано агентом доверия"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Устройство необходимо будет разблокировать вручную"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Быстрый доступ к уведомлениям"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Просматривайте уведомления на заблокированном экране."</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Закрыть"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чаты на первом плане"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Новые чаты из приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" будут появляться в виде всплывающих уведомлений. Чтобы открыть такое уведомление, нажмите на него. Чтобы переместить всплывающее уведомление, перетащите его.\n\nНажмите на всплывающее уведомление"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Чтобы отключить всплывающие уведомления от приложения, нажмите \"Настроить\"."</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Параметры навигации в системе обновлены. Чтобы изменить их, перейдите в настройки."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Чтобы обновить параметры навигации в системе, перейдите в настройки."</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Переход в режим ожидания"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Все"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не удалось загрузить список элементов управления."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Другое"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index ec78baa..17db522 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"ඔබේ කාර්යාල පැතිකඩ කළමනාකරණය කරන්නේ <xliff:g id="ORGANIZATION">%1$s</xliff:g> විසිනි. ඊ-තැපැල්, යෙදුම් සහ වෙබ් අඩවි ඇතුළු ඔබේ කාර්යාල ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, වෙත පැතිකඩ සම්බන්ධ වී ඇත.\n\nඔබ ඔබේ පෞද්ගලික ජාල ක්‍රියාකාරකම් නිරීක්ෂණය කළ හැකි, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> වෙතද සම්බන්ධ වී ඇත."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent මඟින් අඟුලු දමා තබා ගන්න"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"ඔබ අතින් අගුළු අරින තුරු උපකරණය අගුළු වැටි තිබේ"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"දැනුම්දීම් ඉක්මනින් ලබාගන්න"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ඔබ අඟුළු හැරීමට කලින් ඒවා බලන්න"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"එපා ස්තූතියි"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"පහළ වමට ගෙන යන්න"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"පහළ දකුණට ගෙන යන්න"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ඉවතලන්න"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"කල් තියා කතාබස් කර ගෙන යන්න"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> වෙතින් නව කතාබස් බුබුලු ලෙස දිස් වනු ඇත. බුබුලක් විවෘත කිරීමට එය තට්ටු කරන්න. එය ගෙන යාමට අදින්න.\n\nබුබුල තට්ටු කරන්න"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"මෙම යෙදුමෙන් බුබුලු ක්‍රියාවිරහිත කිරීමට කළමනාකරණය කරන්න තට්ටු කරන්න"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"පද්ධති සංචලනය යාවත්කාලීන කළා. වෙනස්කම් සිදු කිරීමට, සැකසීම් වෙත යන්න."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"පද්ධති සංචලනය යාවත්කාලීන කිරීමට සැකසීම් වෙත යන්න"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"පොරොත්තු"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"සියලු"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"සියලු පාලනවල ලැයිස්තුව පූරණය කළ නොහැකි විය."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"වෙනත්"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index bb6ac46..295e700 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane správ, aplikácií a webových stránok.\n\nPripojili ste sa k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Odomknutie udržiava TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Zariadenie zostane uzamknuté, dokým ho ručne neodomknete."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Získavať upozornenia rýchlejšie"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Zobraziť pred odomknutím"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nie, vďaka"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Presunúť doľava nadol"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Presunúť doprava nadol"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavrieť"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zobrazovať čety na popredí"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nové čety z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g> sa budú zobrazovať ako bubliny. Bubliny otvoríte klepnutím na ne. Premiestnite ich presunutím.\n\nKlepnite na bublinu."</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Klepnutím na Spravovať vypnite bubliny z tejto aplikácie"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigácia v systéme bola aktualizovaná. Ak chcete vykonať zmeny, prejdite do Nastavení."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Prejdite do Nastavení a aktualizujte navigáciu v systéme"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Pohotovostný režim"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Všetko"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Zoznam všetkých ovl. prvkov sa nepodarilo načítať."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iné"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5280f6e..b524749 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ohranja odklenjeno"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Naprava bo ostala zaklenjena, dokler je ročno ne odklenete."</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Hitrejše prejemanje obvestil"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Oglejte si jih pred odklepanjem"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ne, hvala"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premakni spodaj levo"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premakni spodaj desno"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Opusti"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Klepete obdrži v ospredju"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Novi klepeti v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> bodo prikazani kot oblački. Dotaknite se oblačka, da ga odprete. Povlecite, da ga premaknete.\n\nDotaknite se oblačka"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dotaknite se »Upravljanje«, da izklopite oblačke iz te aplikacije"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Krmarjenje po sistemu je posodobljeno. Če želite opraviti spremembe, odprite nastavitve."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Če želite posodobiti krmarjenje po sistemu, odprite nastavitve"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Stanje pripravljenosti"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Vse"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Seznama vseh kontrolnikov ni bilo mogoče naložiti."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Drugo"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index c1a32c5..2e83d25 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profili është i lidhur me <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd të punës në rrjet, duke përfshirë mail-et, aplikacionet dhe sajtet e uebit.\n\nJe lidhur gjithashtu edhe me <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, i cili mund të monitorojë aktivitetin tënd personal në rrjet."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Mbajtur shkyçur nga TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Pajisje do të qëndrojë e kyçur derisa ta shkyçësh manualisht"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Merr njoftime më shpejt"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Shikoji para se t\'i shkyçësh"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Jo, faleminderit!"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Mbaji bisedat në plan të parë"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Bisedat e reja nga <xliff:g id="APP_NAME">%1$s</xliff:g> do të shfaqen si flluska. Trokit mbi një flluskë për ta hapur atë. Zvarrit për ta zhvendosur atë.\n\nTrokit mbi flluskë"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trokit \"Menaxho\" për të çaktivizuar flluskat nga ky aplikacion"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Navigimi i sistemit u përditësua. Për të bërë ndryshime, shko te \"Cilësimet\"."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Shko te \"Cilësimet\" për të përditësuar navigimin e sistemit"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Në gatishmëri"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Të gjitha"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Lista e të gjitha kontrolleve nuk mund të ngarkohej."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Tjetër"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 87c9d3f..f77d4a2 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -561,6 +561,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Поуздани агент спречава закључавање"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Уређај ће остати закључан док га не откључате ручно"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Брже добијајте обавештења"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Прегледајте их пре откључавања"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Не, хвала"</string>
@@ -984,12 +985,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести доле лево"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести доле десно"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Одбаци"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Нека поруке ћаскања остану у првом плану"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Нове поруке ћаскања из апликације <xliff:g id="APP_NAME">%1$s</xliff:g> ће се приказати као облачићи. Додирните облачић да бисте га отворили. Превуците да бисте га преместили.\n\nДодирните облачић"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навигација система је ажурирана. Да бисте унели измене, идите у Подешавања."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Идите у Подешавања да бисте ажурирали навигацију система"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Стање приправности"</string>
@@ -1010,4 +1008,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Све"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Учитавање листе свих контрола није успело."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Друго"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c497574..76635ee 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Jobbprofilen hanteras av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen är ansluten till <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> som kan bevaka din nätverksaktivitet på jobbet, exempelvis e-post, appar och webbplatser.\n\nDu är även ansluten till <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> som kan bevaka din privata nätverksaktivitet."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Hålls olåst med TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Enheten förblir låst tills du låser upp den manuellt"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Få aviseringar snabbare"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Visa dem innan du låser upp"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Nej tack"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytta längst ned till vänster"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytta längst ned till höger"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Stäng"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Håll chattar i förgrunden"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Nya chattar från <xliff:g id="APP_NAME">%1$s</xliff:g> visas som bubblor. Tryck på en bubbla som du vill öppna. Flytta den genom att dra.\n\nTryck på bubblan"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Tryck på Hantera för att stänga av bubblor från den här appen"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Systemnavigeringen har uppdaterats. Öppna inställningarna om du vill ändra något."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Öppna inställningarna och uppdatera systemnavigeringen"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Viloläge"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Alla"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Listan med alla kontroller kunde inte läsas in."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Övrigt"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8d2b137..3a5d6ce 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\n Umeunganishwa pia kwenye  <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa binafsi."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Imefunguliwa na kipengele cha kutathmini hali ya kuaminika"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Pata arifa kwa haraka"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Zitazame kabla hujafungua"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hapana"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Zipe gumzo kipaumbele"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Gumzo mpya kutoka <xliff:g id="APP_NAME">%1$s</xliff:g> zitaonekana kama viputo. Gusa kiputo ili ukifungue. Buruta ili ukisogeze.\n\nGusa kiputo"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Gusa Dhibiti ili uzime viputo kwenye programu hii"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ubadilishe, nenda kwenye Mipangilio."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Vyote"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Imeshindwa kupakia orodha ya vidhibiti vyote."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Nyingine"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 3f1ddbd..1583bf8 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -63,18 +63,12 @@
     <string name="usb_debugging_allow" msgid="1722643858015321328">"அனுமதி"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"USB பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string>
     <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் USB பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க, முதன்மைப் பயனருக்கு மாறவும்."</string>
-    <!-- no translation found for wifi_debugging_title (7300007687492186076) -->
-    <skip />
-    <!-- no translation found for wifi_debugging_message (5461204211731802995) -->
-    <skip />
-    <!-- no translation found for wifi_debugging_always (2968383799517975155) -->
-    <skip />
-    <!-- no translation found for wifi_debugging_allow (4573224609684957886) -->
-    <skip />
-    <!-- no translation found for wifi_debugging_secondary_user_title (2493201475880517725) -->
-    <skip />
-    <!-- no translation found for wifi_debugging_secondary_user_message (4492383073970079751) -->
-    <skip />
+    <string name="wifi_debugging_title" msgid="7300007687492186076">"இந்த நெட்வொர்க்கில் வயர்லெஸ் பிழைதிருத்தத்தை அனுமதிக்கவா?"</string>
+    <string name="wifi_debugging_message" msgid="5461204211731802995">"நெட்வொர்க் பெயர் (SSID)\n<xliff:g id="SSID_0">%1$s</xliff:g>\n\nவைஃபை முகவரி (BSSID)\n<xliff:g id="BSSID_1">%2$s</xliff:g>"</string>
+    <string name="wifi_debugging_always" msgid="2968383799517975155">"இந்த நெட்வொர்க்கில் எப்போதும் அனுமதி"</string>
+    <string name="wifi_debugging_allow" msgid="4573224609684957886">"அனுமதி"</string>
+    <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"வயர்லெஸ் பிழைதிருத்தம் அனுமதிக்கப்படவில்லை"</string>
+    <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"தற்போது இந்தச் சாதனத்தில் உள்நுழைந்துள்ள பயனரால் வயர்லெஸ் பிழைதிருத்தத்தை இயக்க முடியாது. இந்த அம்சத்தை இயக்க முதன்மைப் பயனருக்கு மாறவும்."</string>
     <string name="usb_contaminant_title" msgid="894052515034594113">"USB போர்ட் முடக்கப்பட்டது"</string>
     <string name="usb_contaminant_message" msgid="7730476585174719805">"தேவையற்றவையில் இருந்து உங்கள் சாதனத்தைப் பாதுகாக்க USB போர்ட் முடக்கப்பட்டுள்ளது. மேலும் எந்தத் துணைக் கருவிகளையும் அது கண்டறியாது.\n\nUSB போர்ட்டை மீண்டும் எப்போது பயன்படுத்தலாம் என்பதைப் பற்றி உங்களுக்குத் தெரிவிக்கப்படும்."</string>
     <string name="usb_port_enabled" msgid="531823867664717018">"சார்ஜர்களையும் துணைக்கருவிகளையும் கண்டறிவதற்காக USB போர்ட் இயக்கப்பட்டுள்ளது"</string>
@@ -500,8 +494,7 @@
     <string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"வரலாறு"</string>
     <string name="notification_section_header_gentle" msgid="3044910806569985386">"ஒலியில்லாத அறிவிப்புகள்"</string>
-    <!-- no translation found for notification_section_header_alerting (3168140660646863240) -->
-    <skip />
+    <string name="notification_section_header_alerting" msgid="3168140660646863240">"விழிப்பூட்டல் அறிவிப்புகள்"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ஒலியில்லாத அழைப்புகள் அனைத்தையும் அழிக்கும்"</string>
     <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string>
@@ -565,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"உங்கள் பணிக் கணக்கை <xliff:g id="ORGANIZATION">%1$s</xliff:g> நிர்வகிக்கிறது. மின்னஞ்சல்கள், ஆப்ஸ், இணையதளங்கள் உட்பட உங்கள் பணி நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> உடன் அது இணைக்கப்பட்டுள்ளது.\n\nஉங்கள் தனிப்பட்ட நெட்வொர்க் செயல்பாட்டைக் கண்காணிக்கக்கூடிய <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> உடனும் இணைக்கப்பட்டுள்ளீர்கள்."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent இதைத் திறந்தே வைத்துள்ளது"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"நீங்கள் கைமுறையாகத் திறக்கும் வரை, சாதனம் பூட்டப்பட்டிருக்கும்"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"விரைவாக அறிவிப்புகளைப் பெறுதல்"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"திறக்கும் முன் அவற்றைப் பார்க்கவும்"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"வேண்டாம்"</string>
@@ -700,10 +695,8 @@
     <string name="notification_channel_summary_low" msgid="7300447764759926720">"ஒலியோ அதிர்வோ இல்லாமல் முழு கவனம் செலுத்த உதவும்."</string>
     <string name="notification_channel_summary_default" msgid="3539949463907902037">"ஒலியோ அதிர்வோ ஏற்படுத்தி உங்கள் கவனத்தை ஈர்க்கும்."</string>
     <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"இந்த உள்ளடக்கத்திற்கான மிதக்கும் ஷார்ட்கட் மூலம் உங்கள் கவனத்தைப் பெற்றிருக்கும்."</string>
-    <!-- no translation found for bubble_overflow_empty_title (3120029421991510842) -->
-    <skip />
-    <!-- no translation found for bubble_overflow_empty_subtitle (198257239740933131) -->
-    <skip />
+    <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
+    <string name="bubble_overflow_empty_subtitle" msgid="198257239740933131">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்."</string>
     <string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
     <string name="notification_multichannel_desc" msgid="7414593090056236179">"இந்த அறிவுப்புக் குழுக்களை இங்கே உள்ளமைக்க இயலாது"</string>
     <string name="notification_delegate_header" msgid="1264510071031479920">"ப்ராக்ஸியான அறிவிப்பு"</string>
@@ -1003,15 +996,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"விரைவுக் கட்டுப்பாடுகள்"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"கட்டுப்பாடுகளைச் சேர்த்தல்"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"எந்த ஆப்ஸிலிருந்து கட்டுப்பாடுகளைச் சேர்க்க வேண்டும் என்பதைத் தேர்ந்தெடுங்கள்"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> கட்டுப்பாடுகள் சேர்க்கப்பட்டன.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> கட்டுப்பாடு சேர்க்கப்பட்டது.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"கட்டுப்பாடுகள்"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"விரைவு அணுகலுக்கான கட்டுப்பாடுகளைத் தேர்ந்தெடுங்கள்"</string>
-    <!-- no translation found for controls_favorite_header_favorites (3118600046217493471) -->
+    <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"பிடித்தவை"</string>
+    <string name="controls_favorite_header_all" msgid="7507855973418969992">"எல்லாம்"</string>
+    <string name="controls_favorite_load_error" msgid="2533215155804455348">"எல்லா கட்டுப்பாடுகளின் பட்டியலை ஏற்ற முடியவில்லை."</string>
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"பிற"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
     <skip />
-    <!-- no translation found for controls_favorite_header_all (7507855973418969992) -->
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
     <skip />
-    <!-- no translation found for controls_favorite_load_error (2533215155804455348) -->
-    <skip />
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index dd8dcdf..2442eff 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent ద్వారా అన్‌లాక్ చేయబడింది"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"మీరు మాన్యువల్‌గా అన్‌లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"నోటిఫికేషన్‌లను వేగంగా పొందండి"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"వీటిని మీరు అన్‌లాక్ చేయకముందే చూడండి"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"వద్దు, ధన్యవాదాలు"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"దిగువ ఎడమవైపునకు తరలించు"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"చాట్‌లను ముందుగా ఉంచండి"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> నుండి వచ్చే కొత్త చాట్‌లు బబుల్‌లుగా కనిపిస్తాయి. దానిని తెరవడానికి బబుల్‌ను ట్యాప్ చేయండి. దానిని తరలించడానికి లాగండి.\n\nబబుల్‌ను ట్యాప్ చేయండి"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"ఈ యాప్ నుండి వచ్చే బబుల్‌లను ఆఫ్ చేయడానికి మేనేజ్ బటన్‌ను ట్యాప్ చేయండి"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"సిస్టమ్ నావిగేషన్ అప్‌డేట్ చేయబడింది. మార్పులు చేయడానికి, సెట్టింగ్‌లకు వెళ్లండి."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"సిస్టమ్ నావిగేషన్‌ను అప్‌డేట్ చేయడానికి సెట్టింగ్‌లకు వెళ్లండి"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"స్టాండ్‌బై"</string>
@@ -994,12 +993,20 @@
     <string name="quick_controls_title" msgid="525285759614231333">"త్వరిత నియంత్రణలు"</string>
     <string name="controls_providers_title" msgid="8844124515157926071">"నియంత్రణలను జోడించండి"</string>
     <string name="controls_providers_subtitle" msgid="8187768950110836569">"దాని నుండి నియంత్రణలను జోడించేలా ఒక యాప్‌ను ఎంచుకోండి"</string>
-    <!-- no translation found for controls_number_of_favorites (1057347832073807380) -->
+    <plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
+      <item quantity="other"><xliff:g id="NUMBER_1">%s</xliff:g> కంట్రోల్‌లు యాడ్ అయ్యాయి.</item>
+      <item quantity="one"><xliff:g id="NUMBER_0">%s</xliff:g> కంట్రోల్ యాడ్ అయింది.</item>
+    </plurals>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"నియంత్రణలు"</string>
     <string name="controls_favorite_subtitle" msgid="4049644994401173949">"త్వరిత యాక్సెస్ కోసం నియంత్రణలను ఎంచుకోండి"</string>
     <string name="controls_favorite_header_favorites" msgid="3118600046217493471">"ఇష్టమైనవి"</string>
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"అన్ని"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"అన్ని నియంత్రణలు గల జాబితాను లోడ్ చేయలేకపోయాము."</string>
-    <!-- no translation found for controls_favorite_other_zone_header (9089613266575525252) -->
+    <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"ఇతరం"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index d45b7dc..866eb59 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> เป็นผู้จัดการโปรไฟล์งานของคุณ โปรไฟล์ดังกล่าวเชื่อมต่ออยู่กับ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายของคุณ รวมถึงอีเมล แอป และเว็บไซต์\n\nคุณยังเชื่อมต่ออยู่กับ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ด้วย ซึ่งสามารถตรวจสอบกิจกรรมในเครือข่ายส่วนตัวของคุณ"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ปลดล็อกไว้โดย TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"อุปกรณ์จะล็อกจนกว่าคุณจะปลดล็อกด้วยตนเอง"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"รับการแจ้งเตือนเร็วขึ้น"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"ดูก่อนปลดล็อก"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"ไม่เป็นไร"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ย้ายไปด้านซ้ายล่าง"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ย้ายไปด้านขาวล่าง"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"ปิด"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"เข้าถึงแชทได้ง่ายๆ"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"แชทใหม่จาก <xliff:g id="APP_NAME">%1$s</xliff:g> จะปรากฏเป็นบับเบิล แตะบับเบิลเพื่อเปิดแชท ลากเพื่อย้ายตำแหน่ง\n\nแตะบับเบิล"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"แตะ \"จัดการ\" เพื่อปิดบับเบิลจากแอปนี้"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"อัปเดตการไปยังส่วนต่างๆ ของระบบแล้ว หากต้องการเปลี่ยนแปลง ให้ไปที่การตั้งค่า"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ไปที่การตั้งค่าเพื่ออัปเดตการไปยังส่วนต่างๆ ของระบบ"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"สแตนด์บาย"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"ทั้งหมด"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"โหลดรายการตัวควบคุมทั้งหมดไม่ได้"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"อื่นๆ"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7cecf13..cdfe732 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Pinamamahalaan ng <xliff:g id="ORGANIZATION">%1$s</xliff:g> ang iyong profile sa trabaho. Nakakonekta ang profile sa <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong network sa trabaho, kasama ang mga email, app, at website.\n\nNakakonekta ka rin sa <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, na maaaring sumubaybay sa aktibidad sa iyong personal na network."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Pinanatiling naka-unlock ng TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Mananatiling naka-lock ang device hanggang sa manual mong i-unlock"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Kunin ang notification nang mas mabilis"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Tingnan ang mga ito bago ka mag-unlock"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hindi"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ilipat sa kaliwa sa ibaba"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ilipat sa kanan sa ibaba"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"I-dismiss"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Panatilihing nasa harap ang mga chat"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Lalabas ang mga bagong chat mula sa <xliff:g id="APP_NAME">%1$s</xliff:g> bilang mga bubble. I-tap ang isang bubble para buksan ito. I-drag ito para ilipat ito.\n\nI-tap ang bubble"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"I-tap ang Pamahalaan para i-off ang mga bubble mula sa app na ito"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Na-update na ang pag-navigate ng system. Para gumawa ng mga pagbabago, pumunta sa Mga Setting."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Pumunta sa Mga Setting para i-update ang pag-navigate sa system"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Naka-standby"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Lahat"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Hindi ma-load ang listahan ng lahat ng control."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Iba pa"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 150363e..8d2d98b 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. Profil; e-postalar, uygulamalar ve web siteleri de dahil olmak üzere iş ağı etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\nAyrıca, kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tarafından kilit açık tutuldu"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirimleri daha hızlı alın"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Kilidi açmadan bildirimleri görün"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Hayır, teşekkürler"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sol alta taşı"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sağ alta taşı"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kapat"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Sohbetleri önde tutma"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> adlı kişi ile yeni sohbetler balon olarak görünür. Açmak için balona dokunun. Taşımak için sürükleyin.\n\nBalona dokunun"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu uygulamanın balonlarını kapatmak için Yönet\'e dokunun"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Sistemde gezinme yöntemi güncellendi. Değişiklik yapmak için Ayarlar\'a gidin."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Sistemde gezinme yöntemini güncellemek için Ayarlar\'a gidin"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Beklemeye alınıyor"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tümü"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Tüm kontrollerin listesi yüklenemedi."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Diğer"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 347532d..c6bec40 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -564,6 +564,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Вашим робочим профілем керує адміністратор організації <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Цей профіль під’єднано до додатка <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, який може відстежувати вашу активність у мережі, зокрема а електронній пошті, додатках і на веб-сайтах.\n\nВаш профіль також під’єднано до додатка <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, який може відстежувати вашу особисту активність у мережі."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Розблоковує довірчий агент"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Пристрій залишатиметься заблокованим, доки ви не розблокуєте його вручну"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Швидше отримуйте сповіщення"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Переглядайте сповіщення, перш ніж розблокувати екран"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ні, дякую"</string>
@@ -989,12 +990,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Чати завжди під рукою"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Нові чати з додатка <xliff:g id="APP_NAME">%1$s</xliff:g> з\'являтимуться як спливаючі сповіщення. Щоб відкрити чат, натисніть сповіщення. Щоб перемістити сповіщення, потягніть його.\n\nНатисніть спливаюче сповіщення"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Керувати\", щоб вимкнути спливаючі сповіщення для цього додатка"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Навігацію в системі оновлено. Щоб внести зміни, перейдіть у налаштування."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Перейдіть у налаштування, щоб оновити навігацію в системі"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Режим очікування"</string>
@@ -1016,4 +1014,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Усі"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Не вдалося завантажити список усіх елементів керування."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Інше"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index a1523bf..cc5f3c5 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -558,6 +558,8 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ پروفائل <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے دفتری نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے ذاتی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"ٹرسٹ ایجنٹ نے غیر مقفل رکھا ہے"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
+    <!-- no translation found for keyguard_indication_trust_unlocked_plugged_in (2323452175329362855) -->
+    <skip />
     <string name="hidden_notifications_title" msgid="1782412844777612795">"تیزی سے اطلاعات حاصل کریں"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"غیر مقفل کرنے سے پہلے انہیں دیکھیں"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"نہیں شکریہ"</string>
@@ -979,12 +981,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نیچے بائیں جانب لے جائیں"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نیچے دائیں جانب لے جائیں"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"برخاست کریں"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"چیٹس سامنے رکھیں"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی نئی چیٹس بلبلوں کے طور پر ظاہر ہوں گی۔ اسے کھولنے کے لیے کسی بلبلہ کو تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔\n\nبلبلہ کو تھپتھپائیں"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"اس ایپ سے بلبلوں کو آف کرنے کے لیے نظم کریں پر تھپتھپائیں"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string>
@@ -1004,4 +1003,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"تمام"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"تمام کنٹرولز کی فہرست لوڈ نہیں کی جا سکی۔"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"دیگر"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7192a8e..6ceaeeb 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent tomonidan ochilgan"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Bildirishnomalarni tezroq oling"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ularni qulfdan chiqarishdan oldin ko‘ring"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Kerak emas"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Quyi chapga surish"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Chatlar asosiy planda"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasidan yangi chatlar bulutchalar shaklida chiqadi. Uni ochish uchun bulutchani bosing. Uni surish uchun torting.\n\nBulutchani bosing"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Bu ilova bulutchalarini faolsizlantirish uchun Boshqarish tugmasini bosing"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Tizim navigatsiyasi yangilandi. Buni Sozlamalar orqali oʻzgartirishingiz mumkin."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Tizim navigatsiyasini yangilash uchun Sozlamalarni oching"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Kutib turing"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Hammasi"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Boshqaruv elementlarining barchasi yuklanmadi."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Boshqa"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index a9dd01d..37f71c0 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Hồ sơ công việc của bạn do <xliff:g id="ORGANIZATION">%1$s</xliff:g> quản lý. Hồ sơ này được kết nối với <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng của bạn, bao gồm email, ứng dụng và trang web.\n\nBạn cũng đang kết nối với <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ứng dụng này có thể giám sát hoạt động mạng cá nhân của bạn."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Luôn được TrustAgent mở khóa"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Thiết bị sẽ vẫn bị khóa cho tới khi bạn mở khóa theo cách thủ công"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Nhận thông báo nhanh hơn"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Xem thông báo trước khi bạn mở khóa"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Ko, cảm ơn"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Chuyển tới dưới cùng bên trái"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Chuyển tới dưới cùng bên phải"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loại bỏ"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Giữ cuộc trò chuyện trên nền trước"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Các cuộc trò chuyện mới từ ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> sẽ hiển thị dưới dạng bong bóng. Hãy nhấn vào bong bóng để mở. Kéo để di chuyển cuộc trò chuyện.\n\nNhấn vào bong bóng"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Nhấn vào nút Quản lý để tắt bong bóng từ ứng dụng này"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Đã cập nhật chế độ di chuyển trên hệ thống. Để thay đổi, hãy chuyển đến phần Cài đặt."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Chuyển đến phần Cài đặt để cập nhật chế độ di chuyển trên hệ thống"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Chế độ chờ"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Tất cả"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Không thể tải danh sách tất cả tùy chọn điều khiển."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Khác"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index e80a624..119767b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”负责管理,且已连接到“<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>”(该应用能够监控您的工作网络活动,其中包括收发电子邮件、使用应用和浏览网站)。\n\n此外,您还连接到了“<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>”(该应用能够监控您的个人网络活动)。"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由 TrustAgent 保持解锁状态"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"在您手动解锁之前,设备会保持锁定状态"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"更快捷地查看通知"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"无需解锁即可查看通知"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下角"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下角"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"关闭"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"让聊天在前台运行"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"来自<xliff:g id="APP_NAME">%1$s</xliff:g>的新聊天消息会显示为气泡。点按某个气泡可将其打开。拖动即可移动气泡。\n\n点按该气泡"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"点按“管理”按钮,可关闭来自此应用的气泡"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系统导航已更新。要进行更改,请转到“设置”。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"转到“设置”即可更新系统导航"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待机"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"无法加载所有控件的列表。"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 4787b9b..8a3687f 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,此應用程式可以監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n您亦已連結至「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」,此應用程式可以監控您的個人網絡活動。"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由信任的代理保持解鎖狀態"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"裝置將保持上鎖,直到您手動解鎖"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"更快取得通知"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"解鎖前顯示"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了,謝謝"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移去左下角"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移去右下角"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"保持即時通訊在最前面"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的新即時通訊將以小視窗形式顯示。輕按小視窗即可開啟。拖曳即可移動。\n\n輕按小視窗"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕按「管理」即可關閉此應用程式的小視窗"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統導覽已更新。如需變更,請前往「設定」。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"前往「設定」更新系統導覽"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整控制項清單。"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 3158a30..16ee960 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"你的工作資料夾是由「<xliff:g id="ORGANIZATION">%1$s</xliff:g>」所管理。由於該設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,因此你的網路活動 (包括收發電子郵件、使用應用程式和瀏覽網站) 可能會受到這個應用程式監控。\n\n此外,你還與「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」建立了連結,因此你的個人網路活動也可能會受到該應用程式監控。"</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"由 TrustAgent 維持解鎖狀態"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"在你手動解鎖前,裝置將保持鎖定狀態"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"更快取得通知"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"解鎖前顯示"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"不用了,謝謝"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"讓即時通訊繼續在前景執行"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"系統會以泡泡形式顯示來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的新即時通訊。輕觸泡泡即可開啟,拖曳則可移動泡泡。\n\n輕觸泡泡"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"輕觸 [管理] 即可關閉來自這個應用程式的泡泡"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"系統操作機制已更新。如要進行變更,請前往「設定」。"</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"請前往「設定」更新系統操作機制"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"待機"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"全部"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"無法載入完整的控制項清單。"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"其他"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e94a8ab..7e2b53e 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -558,6 +558,7 @@
     <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Iphrofayela yakho yomsebenzi iphethwe i-<xliff:g id="ORGANIZATION">%1$s</xliff:g>. Iphrofayela ixhumeke ku-<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, engaqapha umsebenzi wakho wenethiwekhi, ofaka ama-imeyili, izinhlelo zokusebenza, namawebhusayithi.\n\nFuthi uxhumeke ku-<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, engaqapha umsebenzi wakho siqu wenethiwekhi."</string>
     <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Igcinwa ivuliwe ngo-TrustAgent"</string>
     <string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Idivayisi izohlala ikhiyekile uze uyivule ngokwenza"</string>
+    <string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
     <string name="hidden_notifications_title" msgid="1782412844777612795">"Thola izaziso ngokushesha"</string>
     <string name="hidden_notifications_text" msgid="5899627470450792578">"Ibone ngaphambi kokuthi uyivule"</string>
     <string name="hidden_notifications_cancel" msgid="4805370226181001278">"Cha ngiyabonga"</string>
@@ -979,12 +980,9 @@
     <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Hambisa inkinobho ngakwesokunxele"</string>
     <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Hambisa inkinobho ngakwesokudla"</string>
     <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cashisa"</string>
-    <!-- no translation found for bubbles_user_education_title (3385222165904578710) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_description (6663205638091146934) -->
-    <skip />
-    <!-- no translation found for bubbles_user_education_manage (1391639189507036423) -->
-    <skip />
+    <string name="bubbles_user_education_title" msgid="3385222165904578710">"Gcina izingxoxo ziphambili"</string>
+    <string name="bubbles_user_education_description" msgid="6663205638091146934">"Izingxoxo ezintsha kusuka ku-<xliff:g id="APP_NAME">%1$s</xliff:g>zizovela njengamabhamuza. Thepha ibhamuza ukuze ulivule. Hudula ukuze ulisuse.\n\nThepha ibhamuza"</string>
+    <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Thepha okuthi Phatha ukuvala amabhamuza kusuka kulolu hlelo lokusebenza"</string>
     <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Ukuzulazula kwesistimu kubuyekeziwe. Ukuze wenze ushintsho, hamba kokuthi Izilungiselelo."</string>
     <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Hamba kuzilungiselelo ukuze ubuyekeze ukuzulazula kwesistimu"</string>
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Ilindile"</string>
@@ -1004,4 +1002,10 @@
     <string name="controls_favorite_header_all" msgid="7507855973418969992">"Konke"</string>
     <string name="controls_favorite_load_error" msgid="2533215155804455348">"Uhlu lwazo zonke izilawuli alilayishekanga."</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Okunye"</string>
+    <!-- no translation found for controls_dialog_title (8806193219278278442) -->
+    <skip />
+    <!-- no translation found for controls_dialog_ok (7011816381344485651) -->
+    <skip />
+    <!-- no translation found for controls_dialog_message (6292099631702047540) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9437485..291db65 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1249,6 +1249,7 @@
     <dimen name="controls_app_icon_size">32dp</dimen>
     <dimen name="controls_app_icon_frame_side_padding">8dp</dimen>
     <dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
+    <dimen name="controls_app_icon_frame_bottom_padding">@dimen/controls_app_icon_frame_top_padding</dimen>
     <dimen name="controls_app_bottom_margin">8dp</dimen>
     <dimen name="controls_app_text_padding">8dp</dimen>
     <dimen name="controls_app_divider_height">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5b28479..caf22fe 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2646,4 +2646,11 @@
     <string name="controls_dialog_ok">Add to favorites</string>
     <!-- Controls dialog message [CHAR LIMIT=NONE] -->
     <string name="controls_dialog_message"><xliff:g id="app" example="System UI">%s</xliff:g> suggested this control to add to your favorites.</string>
+
+    <!-- Controls PIN entry dialog, switch to alphanumeric keyboard [CHAR LIMIT=100] -->
+    <string name="controls_pin_use_alphanumeric">PIN contains letters or symbols</string>
+    <!-- Controls PIN entry dialog, title [CHAR LIMIT=30] -->
+    <string name="controls_pin_verify">Verify device PIN</string>
+    <!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
+    <string name="controls_pin_instructions">Enter PIN</string>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index ca88f13..aed7c21 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -44,7 +44,9 @@
     public final Rect clipRect;
     public final int prefixOrderIndex;
     public final Point position;
+    public final Rect localBounds;
     public final Rect sourceContainerBounds;
+    public final Rect screenSpaceBounds;
     public final boolean isNotInRecents;
     public final Rect contentInsets;
 
@@ -57,7 +59,9 @@
         isTranslucent = app.isTranslucent;
         clipRect = app.clipRect;
         position = app.position;
+        localBounds = app.localBounds;
         sourceContainerBounds = app.sourceContainerBounds;
+        screenSpaceBounds = app.screenSpaceBounds;
         prefixOrderIndex = app.prefixOrderIndex;
         isNotInRecents = app.isNotInRecents;
         contentInsets = app.contentInsets;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
index 7cfa289..d33c653 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java
@@ -20,6 +20,7 @@
 import android.graphics.PixelFormat;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.util.Size;
 import android.view.SurfaceControl;
 import android.view.SurfaceControlViewHost;
 import android.view.View;
@@ -43,13 +44,27 @@
         mOpacity = opacity;
     }
 
-    /** Called whenever a surface view request is received. */
+    /** See {@link #onReceive(Context, Bundle, View, Size)}. */
     public void onReceive(Context context, Bundle bundle, View view) {
+        onReceive(context, bundle, view, null);
+    }
+
+    /**
+     * Called whenever a surface view request is received.
+     * @param view     the view rendering content, on the receiver end of the surface request.
+     * @param viewSize when {@param viewSize} is not specified, we will use the surface control size
+     *                 to attach the view to the window.
+     */
+    public void onReceive(Context context, Bundle bundle, View view, Size viewSize) {
         if (mSurfaceControlViewHost != null) {
             mSurfaceControlViewHost.die();
         }
         SurfaceControl surfaceControl = SurfaceViewRequestUtils.getSurfaceControl(bundle);
         if (surfaceControl != null) {
+            if (viewSize == null) {
+                viewSize = new Size(surfaceControl.getWidth(), surfaceControl.getHeight());
+            }
+
             IBinder hostToken = SurfaceViewRequestUtils.getHostToken(bundle);
 
             WindowlessWindowManager windowlessWindowManager =
@@ -59,12 +74,22 @@
                     context.getDisplayNoVerify(), windowlessWindowManager);
             WindowManager.LayoutParams layoutParams =
                     new WindowManager.LayoutParams(
-                            surfaceControl.getWidth(),
-                            surfaceControl.getHeight(),
+                            viewSize.getWidth(),
+                            viewSize.getHeight(),
                             WindowManager.LayoutParams.TYPE_APPLICATION,
                             WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                             mOpacity);
 
+            // This aspect scales the view to fit in the surface and centers it
+            final float scale = Math.min(surfaceControl.getWidth() / (float) viewSize.getWidth(),
+                    surfaceControl.getHeight() / (float) viewSize.getHeight());
+            view.setScaleX(scale);
+            view.setScaleY(scale);
+            view.setPivotX(0);
+            view.setPivotY(0);
+            view.setTranslationX((surfaceControl.getWidth() - scale * viewSize.getWidth()) / 2);
+            view.setTranslationY((surfaceControl.getHeight() - scale * viewSize.getHeight()) / 2);
+
             mSurfaceControlViewHost.addView(view, layoutParams);
         }
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java
index 0cbd541..4409276 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java
@@ -36,7 +36,7 @@
     }
 
     /**
-     * Retrieves the SurfaceControl from an Intent created by
+     * Retrieves the SurfaceControl from a bundle created by
      * {@link #createSurfaceBundle(SurfaceView)}.
      **/
     public static SurfaceControl getSurfaceControl(Bundle bundle) {
@@ -44,7 +44,7 @@
     }
 
     /**
-     * Retrieves the input token from an Intent created by
+     * Retrieves the input token from a bundle created by
      * {@link #createSurfaceBundle(SurfaceView)}.
      **/
     public static @Nullable IBinder getHostToken(Bundle bundle) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 1c6223b..9e9b9dc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -37,7 +37,8 @@
     public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
     public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
     public void onActivityUnpinned() { }
-    public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
+    public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask) { }
     public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
     public void onActivityDismissingDockedStack() { }
     public void onActivityLaunchOnSecondaryDisplayFailed() { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index cbdd3f8..ce9cbab 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -30,6 +30,7 @@
 import android.os.Trace;
 import android.util.Log;
 
+import com.android.internal.os.SomeArgs;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.util.ArrayList;
@@ -120,11 +121,14 @@
     }
 
     @Override
-    public void onPinnedActivityRestartAttempt(boolean clearedTask)
-            throws RemoteException {
-        mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
-        mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
-                .sendToTarget();
+    public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask) throws RemoteException {
+        final SomeArgs args = SomeArgs.obtain();
+        args.arg1 = task;
+        args.argi1 = homeTaskVisible ? 1 : 0;
+        args.argi2 = clearedTask ? 1 : 0;
+        mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT);
+        mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
     }
 
     @Override
@@ -236,7 +240,7 @@
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
         private static final int ON_ACTIVITY_PINNED = 3;
-        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+        private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
         private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
         private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
         private static final int ON_TASK_PROFILE_LOCKED = 8;
@@ -296,10 +300,14 @@
                         }
                         break;
                     }
-                    case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+                    case ON_ACTIVITY_RESTART_ATTEMPT: {
+                        final SomeArgs args = (SomeArgs) msg.obj;
+                        final RunningTaskInfo task = (RunningTaskInfo) args.arg1;
+                        final boolean homeTaskVisible = args.argi1 != 0;
+                        final boolean clearedTask = args.argi2 != 0;
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
-                                    msg.arg1 != 0);
+                            mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+                                    homeTaskVisible, clearedTask);
                         }
                         break;
                     }
@@ -419,6 +427,9 @@
                     }
                 }
             }
+            if (msg.obj instanceof SomeArgs) {
+                ((SomeArgs) msg.obj).recycle();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 0367464..2200b22 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -43,6 +43,7 @@
 import com.android.systemui.util.InjectionInflationController;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -74,8 +75,8 @@
     private final ContentObserver mContentObserver =
             new ContentObserver(mMainHandler) {
                 @Override
-                public void onChange(boolean selfChange, Uri uri, int userId) {
-                    super.onChange(selfChange, uri, userId);
+                public void onChange(boolean selfChange, Collection<Uri> uris,
+                        int flags, int userId) {
                     if (Objects.equals(userId,
                             mCurrentUserObservable.getCurrentUser().getValue())) {
                         reload();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b6152da..a868cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -71,11 +71,12 @@
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -288,6 +289,7 @@
     @Inject Lazy<NotificationLogger> mNotificationLogger;
     @Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
     @Inject Lazy<NotificationFilter> mNotificationFilter;
+    @Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider;
     @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
     @Inject Lazy<SmartReplyController> mSmartReplyController;
     @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -487,6 +489,8 @@
         mProviders.put(NotificationViewHierarchyManager.class,
                 mNotificationViewHierarchyManager::get);
         mProviders.put(NotificationFilter.class, mNotificationFilter::get);
+        mProviders.put(NotificationInterruptionStateProvider.class,
+                mNotificationInterruptionStateProvider::get);
         mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
         mProviders.put(SmartReplyController.class, mSmartReplyController::get);
         mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
deleted file mode 100644
index ad2e002..0000000
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.content.Context;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.leak.RotationUtils;
-
-/**
- * Layout for placing two containers at a specific physical position on the device, relative to the
- * device's hardware, regardless of screen rotation.
- */
-public class HardwareUiLayout extends MultiListLayout implements Tunable {
-
-    private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
-    private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
-    private final int[] mTmp2 = new int[2];
-    private ViewGroup mList;
-    private ViewGroup mSeparatedView;
-    private int mOldHeight;
-    private boolean mAnimating;
-    private AnimatorSet mAnimation;
-    private View mDivision;
-    private HardwareBgDrawable mListBackground;
-    private HardwareBgDrawable mSeparatedViewBackground;
-    private Animator mAnimator;
-    private boolean mCollapse;
-    private int mEndPoint;
-    private boolean mEdgeBleed;
-    private boolean mRoundedDivider;
-    private boolean mRotatedBackground;
-    private boolean mSwapOrientation = true;
-
-    public HardwareUiLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        // Manually re-initialize mRotation to portrait-mode, since this view must always
-        // be constructed in portrait mode and rotated into the correct initial position.
-        mRotation = ROTATION_NONE;
-        updateSettings();
-    }
-
-    @Override
-    protected ViewGroup getSeparatedView() {
-        return findViewById(com.android.systemui.R.id.separated_button);
-    }
-
-    @Override
-    protected ViewGroup getListView() {
-        return findViewById(android.R.id.list);
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        updateSettings();
-        Dependency.get(TunerService.class).addTunable(this, EDGE_BLEED, ROUNDED_DIVIDER);
-        getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
-        Dependency.get(TunerService.class).removeTunable(this);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        updateSettings();
-    }
-
-    private void updateSettings() {
-        mEdgeBleed = Settings.Secure.getInt(getContext().getContentResolver(),
-                EDGE_BLEED, 0) != 0;
-        mRoundedDivider = Settings.Secure.getInt(getContext().getContentResolver(),
-                ROUNDED_DIVIDER, 0) != 0;
-        updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
-        mListBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, getContext());
-        mSeparatedViewBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed,
-                getContext());
-        if (mList != null) {
-            mList.setBackground(mListBackground);
-            mSeparatedView.setBackground(mSeparatedViewBackground);
-            requestLayout();
-        }
-    }
-
-    private void updateEdgeMargin(int edge) {
-        if (mList != null) {
-            MarginLayoutParams params = (MarginLayoutParams) mList.getLayoutParams();
-            if (mRotation == ROTATION_LANDSCAPE) {
-                params.topMargin = edge;
-            } else if (mRotation == ROTATION_SEASCAPE) {
-                params.bottomMargin = edge;
-            } else {
-                params.rightMargin = edge;
-            }
-            mList.setLayoutParams(params);
-        }
-
-        if (mSeparatedView != null) {
-            MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
-            if (mRotation == ROTATION_LANDSCAPE) {
-                params.topMargin = edge;
-            } else if (mRotation == ROTATION_SEASCAPE) {
-                params.bottomMargin = edge;
-            } else {
-                params.rightMargin = edge;
-            }
-            mSeparatedView.setLayoutParams(params);
-        }
-    }
-
-    private int getEdgePadding() {
-        return getContext().getResources().getDimensionPixelSize(R.dimen.edge_margin);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mList == null) {
-            if (getChildCount() != 0) {
-                mList = getListView();
-                mList.setBackground(mListBackground);
-                mSeparatedView = getSeparatedView();
-                mSeparatedView.setBackground(mSeparatedViewBackground);
-                updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
-                mOldHeight = mList.getMeasuredHeight();
-
-                // Must be called to initialize view rotation correctly.
-                // Requires LayoutParams, hence why this isn't called during the constructor.
-                updateRotation();
-            } else {
-                return;
-            }
-        }
-        int newHeight = mList.getMeasuredHeight();
-        if (newHeight != mOldHeight) {
-            animateChild(mOldHeight, newHeight);
-        }
-
-        post(() -> updatePaddingAndGravityIfTooTall());
-        post(() -> updatePosition());
-    }
-
-    public void setSwapOrientation(boolean swapOrientation) {
-        mSwapOrientation = swapOrientation;
-    }
-
-    private void updateRotation() {
-        int rotation = RotationUtils.getRotation(getContext());
-        if (rotation != mRotation) {
-            rotate(mRotation, rotation);
-            mRotation = rotation;
-        }
-    }
-
-    /**
-     *  Requires LayoutParams to be set to work correctly, and therefore must be run after after
-     *  the HardwareUILayout has been added to the view hierarchy.
-     */
-    protected void rotate(int from, int to) {
-        super.rotate(from, to);
-        if (from != ROTATION_NONE && to != ROTATION_NONE) {
-            // Rather than handling this confusing case, just do 2 rotations.
-            rotate(from, ROTATION_NONE);
-            rotate(ROTATION_NONE, to);
-            return;
-        }
-        if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
-            rotateRight();
-        } else {
-            rotateLeft();
-        }
-        if (mAdapter.hasSeparatedItems()) {
-            if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) {
-                // Separated view has top margin, so seascape separated view need special rotation,
-                // not a full left or right rotation.
-                swapLeftAndTop(mSeparatedView);
-            } else if (from == ROTATION_LANDSCAPE) {
-                rotateRight(mSeparatedView);
-            } else {
-                rotateLeft(mSeparatedView);
-            }
-        }
-        if (to != ROTATION_NONE) {
-            if (mList instanceof LinearLayout) {
-                mRotatedBackground = true;
-                mListBackground.setRotatedBackground(true);
-                mSeparatedViewBackground.setRotatedBackground(true);
-                LinearLayout linearLayout = (LinearLayout) mList;
-                if (mSwapOrientation) {
-                    linearLayout.setOrientation(LinearLayout.HORIZONTAL);
-                    setOrientation(LinearLayout.HORIZONTAL);
-                }
-                swapDimens(mList);
-                swapDimens(mSeparatedView);
-            }
-        } else {
-            if (mList instanceof LinearLayout) {
-                mRotatedBackground = false;
-                mListBackground.setRotatedBackground(false);
-                mSeparatedViewBackground.setRotatedBackground(false);
-                LinearLayout linearLayout = (LinearLayout) mList;
-                if (mSwapOrientation) {
-                    linearLayout.setOrientation(LinearLayout.VERTICAL);
-                    setOrientation(LinearLayout.VERTICAL);
-                }
-                swapDimens(mList);
-                swapDimens(mSeparatedView);
-            }
-        }
-    }
-
-    @Override
-    public void onUpdateList() {
-        super.onUpdateList();
-
-        for (int i = 0; i < mAdapter.getCount(); i++) {
-            ViewGroup parent;
-            boolean separated = mAdapter.shouldBeSeparated(i);
-            if (separated) {
-                parent = getSeparatedView();
-            } else {
-                parent = getListView();
-            }
-            View v = mAdapter.getView(i, null, parent);
-            parent.addView(v);
-        }
-    }
-
-    private void rotateRight() {
-        rotateRight(this);
-        rotateRight(mList);
-        swapDimens(this);
-
-        LayoutParams p = (LayoutParams) mList.getLayoutParams();
-        p.gravity = rotateGravityRight(p.gravity);
-        mList.setLayoutParams(p);
-
-        LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
-        separatedViewLayoutParams.gravity = rotateGravityRight(separatedViewLayoutParams.gravity);
-        mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
-        setGravity(rotateGravityRight(getGravity()));
-    }
-
-    private void swapDimens(View v) {
-        ViewGroup.LayoutParams params = v.getLayoutParams();
-        int h = params.width;
-        params.width = params.height;
-        params.height = h;
-        v.setLayoutParams(params);
-    }
-
-    private int rotateGravityRight(int gravity) {
-        int retGravity = 0;
-        int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
-        final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                retGravity |= Gravity.CENTER_VERTICAL;
-                break;
-            case Gravity.RIGHT:
-                retGravity |= Gravity.BOTTOM;
-                break;
-            case Gravity.LEFT:
-            default:
-                retGravity |= Gravity.TOP;
-                break;
-        }
-
-        switch (verticalGravity) {
-            case Gravity.CENTER_VERTICAL:
-                retGravity |= Gravity.CENTER_HORIZONTAL;
-                break;
-            case Gravity.BOTTOM:
-                retGravity |= Gravity.LEFT;
-                break;
-            case Gravity.TOP:
-            default:
-                retGravity |= Gravity.RIGHT;
-                break;
-        }
-        return retGravity;
-    }
-
-    private void rotateLeft() {
-        rotateLeft(this);
-        rotateLeft(mList);
-        swapDimens(this);
-
-        LayoutParams p = (LayoutParams) mList.getLayoutParams();
-        p.gravity = rotateGravityLeft(p.gravity);
-        mList.setLayoutParams(p);
-
-        LayoutParams separatedViewLayoutParams = (LayoutParams) mSeparatedView.getLayoutParams();
-        separatedViewLayoutParams.gravity = rotateGravityLeft(separatedViewLayoutParams.gravity);
-        mSeparatedView.setLayoutParams(separatedViewLayoutParams);
-
-        setGravity(rotateGravityLeft(getGravity()));
-    }
-
-    private int rotateGravityLeft(int gravity) {
-        if (gravity == -1) {
-            gravity = Gravity.TOP | Gravity.START;
-        }
-        int retGravity = 0;
-        int layoutDirection = getLayoutDirection();
-        final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
-        final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-        switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                retGravity |= Gravity.CENTER_VERTICAL;
-                break;
-            case Gravity.RIGHT:
-                retGravity |= Gravity.TOP;
-                break;
-            case Gravity.LEFT:
-            default:
-                retGravity |= Gravity.BOTTOM;
-                break;
-        }
-
-        switch (verticalGravity) {
-            case Gravity.CENTER_VERTICAL:
-                retGravity |= Gravity.CENTER_HORIZONTAL;
-                break;
-            case Gravity.BOTTOM:
-                retGravity |= Gravity.RIGHT;
-                break;
-            case Gravity.TOP:
-            default:
-                retGravity |= Gravity.LEFT;
-                break;
-        }
-        return retGravity;
-    }
-
-    private void rotateLeft(View v) {
-        v.setPadding(v.getPaddingTop(), v.getPaddingRight(), v.getPaddingBottom(),
-                v.getPaddingLeft());
-        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
-        params.setMargins(params.topMargin, params.rightMargin, params.bottomMargin,
-                params.leftMargin);
-        v.setLayoutParams(params);
-    }
-
-    private void rotateRight(View v) {
-        v.setPadding(v.getPaddingBottom(), v.getPaddingLeft(), v.getPaddingTop(),
-                v.getPaddingRight());
-        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
-        params.setMargins(params.bottomMargin, params.leftMargin, params.topMargin,
-                params.rightMargin);
-        v.setLayoutParams(params);
-    }
-
-    private void swapLeftAndTop(View v) {
-        v.setPadding(v.getPaddingTop(), v.getPaddingLeft(), v.getPaddingBottom(),
-                v.getPaddingRight());
-        MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();
-        params.setMargins(params.topMargin, params.leftMargin, params.bottomMargin,
-                params.rightMargin);
-        v.setLayoutParams(params);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        post(() -> updatePosition());
-
-    }
-
-    private void animateChild(int oldHeight, int newHeight) {
-        if (true) return;
-        if (mAnimating) {
-            mAnimation.cancel();
-        }
-        mAnimating = true;
-        mAnimation = new AnimatorSet();
-        mAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimating = false;
-            }
-        });
-        int fromTop = mList.getTop();
-        int fromBottom = mList.getBottom();
-        int toTop = fromTop - ((newHeight - oldHeight) / 2);
-        int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
-        ObjectAnimator top = ObjectAnimator.ofInt(mList, "top", fromTop, toTop);
-        top.addUpdateListener(animation -> mListBackground.invalidateSelf());
-        mAnimation.playTogether(top,
-                ObjectAnimator.ofInt(mList, "bottom", fromBottom, toBottom));
-    }
-
-    public void setDivisionView(View v) {
-        mDivision = v;
-        if (mDivision != null) {
-            mDivision.addOnLayoutChangeListener(
-                    (v1, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
-                            updatePosition());
-        }
-        updatePosition();
-    }
-
-    private void updatePosition() {
-        if (mList == null) return;
-        // If got separated button, setRotatedBackground to false,
-        // all items won't get white background.
-        boolean separated = mAdapter.hasSeparatedItems();
-        mListBackground.setRotatedBackground(separated);
-        mSeparatedViewBackground.setRotatedBackground(separated);
-        if (mDivision != null && mDivision.getVisibility() == VISIBLE) {
-            int index = mRotatedBackground ? 0 : 1;
-            mDivision.getLocationOnScreen(mTmp2);
-            float trans = mRotatedBackground ? mDivision.getTranslationX()
-                    : mDivision.getTranslationY();
-            int viewTop = (int) (mTmp2[index] + trans);
-            mList.getLocationOnScreen(mTmp2);
-            viewTop -= mTmp2[index];
-            setCutPoint(viewTop);
-        } else {
-            setCutPoint(mList.getMeasuredHeight());
-        }
-    }
-
-    private void setCutPoint(int point) {
-        int curPoint = mListBackground.getCutPoint();
-        if (curPoint == point) return;
-        if (getAlpha() == 0 || curPoint == 0) {
-            mListBackground.setCutPoint(point);
-            return;
-        }
-        if (mAnimator != null) {
-            if (mEndPoint == point) {
-                return;
-            }
-            mAnimator.cancel();
-        }
-        mEndPoint = point;
-        mAnimator = ObjectAnimator.ofInt(mListBackground, "cutPoint", curPoint, point);
-        if (mCollapse) {
-            mAnimator.setStartDelay(300);
-            mCollapse = false;
-        }
-        mAnimator.start();
-    }
-
-    // If current power menu height larger then screen height, remove padding to break power menu
-    // alignment and set menu center vertical within the screen.
-    private void updatePaddingAndGravityIfTooTall() {
-        int defaultTopPadding;
-        int viewsTotalHeight;
-        int separatedViewTopMargin;
-        int screenHeight;
-        int totalHeight;
-        int targetGravity;
-        boolean separated = mAdapter.hasSeparatedItems();
-        MarginLayoutParams params = (MarginLayoutParams) mSeparatedView.getLayoutParams();
-        switch (RotationUtils.getRotation(getContext())) {
-            case RotationUtils.ROTATION_LANDSCAPE:
-                defaultTopPadding = getPaddingLeft();
-                viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = separated ? params.leftMargin : 0;
-                screenHeight = getMeasuredWidth();
-                targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
-                break;
-            case RotationUtils.ROTATION_SEASCAPE:
-                defaultTopPadding = getPaddingRight();
-                viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth();
-                separatedViewTopMargin = separated ? params.leftMargin : 0;
-                screenHeight = getMeasuredWidth();
-                targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM;
-                break;
-            default: // Portrait
-                defaultTopPadding = getPaddingTop();
-                viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight();
-                separatedViewTopMargin = separated ? params.topMargin : 0;
-                screenHeight = getMeasuredHeight();
-                targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT;
-                break;
-        }
-        totalHeight = defaultTopPadding + viewsTotalHeight + separatedViewTopMargin;
-        if (totalHeight >= screenHeight) {
-            setPadding(0, 0, 0, 0);
-            setGravity(targetGravity);
-        }
-    }
-
-    @Override
-    public ViewOutlineProvider getOutlineProvider() {
-        return super.getOutlineProvider();
-    }
-
-    public void setCollapse() {
-        mCollapse = true;
-    }
-
-    private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
-        if (mHasOutsideTouch || (mList == null)) {
-            inoutInfo.setTouchableInsets(
-                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
-            return;
-        }
-        inoutInfo.setTouchableInsets(
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
-        inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
-                0, getBottom() - mList.getBottom());
-    };
-
-    private float getAnimationDistance() {
-        return getContext().getResources().getDimension(
-                com.android.systemui.R.dimen.global_actions_panel_width) / 2;
-    }
-
-    @Override
-    public float getAnimationOffsetX() {
-        if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
-            return getAnimationDistance();
-        }
-        return 0;
-    }
-
-    @Override
-    public float getAnimationOffsetY() {
-        switch (RotationUtils.getRotation(getContext())) {
-            case RotationUtils.ROTATION_LANDSCAPE:
-                return -getAnimationDistance();
-            case RotationUtils.ROTATION_SEASCAPE:
-                return getAnimationDistance();
-            default: // Portrait
-                return 0;
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 7ca2308..4240209c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -279,7 +279,8 @@
     /**
      * @return the display id of the virtual display on which bubble contents is drawn.
      */
-    int getDisplayId() {
+    @Override
+    public int getDisplayId() {
         return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index f873f42..ae1438e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -83,11 +83,11 @@
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -169,7 +169,7 @@
     // Callback that updates BubbleOverflowActivity on data change.
     @Nullable private Runnable mOverflowCallback = null;
 
-    private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private IStatusBarService mBarService;
 
     // Used for determining view rect for touch interaction
@@ -279,7 +279,7 @@
             ShadeController shadeController,
             BubbleData data,
             ConfigurationController configurationController,
-            NotificationInterruptStateProvider interruptionStateProvider,
+            NotificationInterruptionStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
@@ -304,7 +304,7 @@
             BubbleData data,
             @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
             ConfigurationController configurationController,
-            NotificationInterruptStateProvider interruptionStateProvider,
+            NotificationInterruptionStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
@@ -316,7 +316,7 @@
         dumpManager.registerDumpable(TAG, this);
         mContext = context;
         mShadeController = shadeController;
-        mNotificationInterruptStateProvider = interruptionStateProvider;
+        mNotificationInterruptionStateProvider = interruptionStateProvider;
         mNotifUserManager = notifUserManager;
         mZenModeController = zenModeController;
         mFloatingContentCoordinator = floatingContentCoordinator;
@@ -632,7 +632,7 @@
         for (NotificationEntry e :
                 mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
             if (savedBubbleKeys.contains(e.getKey())
-                    && mNotificationInterruptStateProvider.shouldBubbleUp(e)
+                    && mNotificationInterruptionStateProvider.shouldBubbleUp(e)
                     && canLaunchInActivityView(mContext, e)) {
                 updateBubble(e, /* suppressFlyout= */ true);
             }
@@ -894,7 +894,7 @@
         boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
                 mContext, entry, previouslyUserCreated, userBlocked);
 
-        if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+        if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
                 && (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
             if (wasAdjusted && !previouslyUserCreated) {
                 // Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
@@ -910,7 +910,7 @@
         boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
                 mContext, entry, previouslyUserCreated, userBlocked);
 
-        boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
+        boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
                 && (canLaunchInActivityView(mContext, entry) || wasAdjusted);
         if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
             // It was previously a bubble but no longer a bubble -- lets remove it
@@ -1175,23 +1175,17 @@
      * status bar, otherwise returns {@link Display#INVALID_DISPLAY}.
      */
     public int getExpandedDisplayId(Context context) {
-        final Bubble bubble = getExpandedBubble(context);
-        return bubble != null ? bubble.getDisplayId() : INVALID_DISPLAY;
-    }
-
-    @Nullable
-    private Bubble getExpandedBubble(Context context) {
         if (mStackView == null) {
-            return null;
+            return INVALID_DISPLAY;
         }
         final boolean defaultDisplay = context.getDisplay() != null
                 && context.getDisplay().getDisplayId() == DEFAULT_DISPLAY;
-        final Bubble expandedBubble = mStackView.getExpandedBubble();
-        if (defaultDisplay && expandedBubble != null && isStackExpanded()
+        final BubbleViewProvider expandedViewProvider = mStackView.getExpandedBubble();
+        if (defaultDisplay && expandedViewProvider != null && isStackExpanded()
                 && !mNotificationShadeWindowController.getPanelExpanded()) {
-            return expandedBubble;
+            return expandedViewProvider.getDisplayId();
         }
-        return null;
+        return INVALID_DISPLAY;
     }
 
     @VisibleForTesting
@@ -1233,6 +1227,17 @@
         }
 
         @Override
+        public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+                boolean clearedTask) {
+            for (Bubble b : mBubbleData.getBubbles()) {
+                if (b.getDisplayId() == task.displayId) {
+                    expandStackAndSelectBubble(b.getKey());
+                    return;
+                }
+            }
+        }
+
+        @Override
         public void onActivityLaunchOnSecondaryDisplayRerouted() {
             if (mStackView != null) {
                 mBubbleData.setExpanded(false);
@@ -1256,7 +1261,7 @@
 
         @Override
         public void onSingleTaskDisplayEmpty(int displayId) {
-            final Bubble expandedBubble = mStackView != null
+            final BubbleViewProvider expandedBubble = mStackView != null
                     ? mStackView.getExpandedBubble()
                     : null;
             int expandedId = expandedBubble != null ? expandedBubble.getDisplayId() : -1;
@@ -1311,7 +1316,7 @@
     private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedStackListener {
         @Override
         public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            if (mStackView != null && mStackView.getBubbleCount() > 0) {
+            if (mStackView != null) {
                 mStackView.post(() -> mStackView.onImeVisibilityChanged(imeVisible, imeHeight));
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
index e800011..19733a5 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java
@@ -59,13 +59,15 @@
         return FORCE_SHOW_USER_EDUCATION || forceShow;
     }
 
-    static String formatBubblesString(List<Bubble> bubbles, Bubble selected) {
+    static String formatBubblesString(List<Bubble> bubbles, BubbleViewProvider selected) {
         StringBuilder sb = new StringBuilder();
         for (Bubble bubble : bubbles) {
             if (bubble == null) {
                 sb.append("   <null> !!!!!\n");
             } else {
-                boolean isSelected = (selected != null && bubble == selected);
+                boolean isSelected = (selected != null
+                        && selected.getKey() != BubbleOverflow.KEY
+                        && bubble == selected);
                 String arrow = isSelected ? "=>" : "  ";
                 sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n",
                         arrow,
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
index 313bb42..4fb2d08 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.bubbles;
 
+import static android.view.Display.INVALID_DISPLAY;
 import static android.view.View.GONE;
 
 import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
@@ -45,7 +46,7 @@
     public static final String KEY = "Overflow";
 
     private BadgedImageView mOverflowBtn;
-    private BubbleExpandedView mOverflowExpandedView;
+    private BubbleExpandedView mExpandedView;
     private LayoutInflater mInflater;
     private Context mContext;
     private Bitmap mIcon;
@@ -63,11 +64,11 @@
     }
 
     void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
-        mOverflowExpandedView = (BubbleExpandedView) mInflater.inflate(
+        mExpandedView = (BubbleExpandedView) mInflater.inflate(
                 R.layout.bubble_expanded_view, parentViewGroup /* root */,
                 false /* attachToRoot */);
-        mOverflowExpandedView.setOverflow(true);
-        mOverflowExpandedView.setStackView(stackView);
+        mExpandedView.setOverflow(true);
+        mExpandedView.setStackView(stackView);
 
         updateIcon(mContext, parentViewGroup);
     }
@@ -124,7 +125,7 @@
 
     @Override
     public BubbleExpandedView getExpandedView() {
-        return mOverflowExpandedView;
+        return mExpandedView;
     }
 
     @Override
@@ -149,7 +150,7 @@
 
     @Override
     public void setContentVisibility(boolean visible) {
-        mOverflowExpandedView.setContentVisibility(visible);
+        mExpandedView.setContentVisibility(visible);
     }
 
     @Override
@@ -167,4 +168,9 @@
     public String getKey() {
         return BubbleOverflow.KEY;
     }
+
+    @Override
+    public int getDisplayId() {
+        return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 8cc10d9..aedd2db 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -126,6 +126,11 @@
     @VisibleForTesting
     static final int FLYOUT_HIDE_AFTER = 5000;
 
+    private static final PhysicsAnimator.SpringConfig FLYOUT_IME_ANIMATION_SPRING_CONFIG =
+            new PhysicsAnimator.SpringConfig(
+                    StackAnimationController.IME_ANIMATION_STIFFNESS,
+                    StackAnimationController.DEFAULT_BOUNCINESS);
+
     /**
      * Interface to synchronize {@link View} state and the screen.
      *
@@ -903,14 +908,8 @@
      * The {@link Bubble} that is expanded, null if one does not exist.
      */
     @Nullable
-    Bubble getExpandedBubble() {
-        if (mExpandedBubble == null
-                || (BubbleExperimentConfig.allowBubbleOverflow(mContext)
-                    && mExpandedBubble.getIconView() == mBubbleOverflow.getBtn()
-                    && BubbleOverflow.KEY.equals(mExpandedBubble.getKey()))) {
-            return null;
-        }
-        return (Bubble) mExpandedBubble;
+    BubbleViewProvider getExpandedBubble() {
+        return mExpandedBubble;
     }
 
     // via BubbleData.Listener
@@ -1240,7 +1239,8 @@
     }
 
     /**
-     * @deprecated use {@link #setExpanded(boolean)} and {@link #setSelectedBubble(Bubble)}
+     * @deprecated use {@link #setExpanded(boolean)} and
+     * {@link BubbleData#setSelectedBubble(Bubble)}
      */
     @Deprecated
     @MainThread
@@ -1282,7 +1282,7 @@
         if (DEBUG_BUBBLE_STACK_VIEW) {
             Log.d(TAG, "animateCollapse");
             Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(),
-                    getExpandedBubble()));
+                    mExpandedBubble));
         }
         updateOverflowBtnVisibility(/* apply */ false);
         mBubbleContainer.cancelAllAnimations();
@@ -1354,8 +1354,23 @@
     public void onImeVisibilityChanged(boolean visible, int height) {
         mStackAnimationController.setImeHeight(visible ? height + mImeOffset : 0);
 
-        if (!mIsExpanded) {
-            mStackAnimationController.animateForImeVisibility(visible);
+        if (!mIsExpanded && getBubbleCount() > 0) {
+            final float stackDestinationY =
+                    mStackAnimationController.animateForImeVisibility(visible);
+
+            // How far the stack is animating due to IME, we'll just animate the flyout by that
+            // much too.
+            final float stackDy =
+                    stackDestinationY - mStackAnimationController.getStackPosition().y;
+
+            // If the flyout is visible, translate it along with the bubble stack.
+            if (mFlyout.getVisibility() == VISIBLE) {
+                PhysicsAnimator.getInstance(mFlyout)
+                        .spring(DynamicAnimation.TRANSLATION_Y,
+                                mFlyout.getTranslationY() + stackDy,
+                                FLYOUT_IME_ANIMATION_SPRING_CONFIG)
+                        .start();
+            }
         }
     }
 
@@ -1371,13 +1386,14 @@
         if (DEBUG_BUBBLE_STACK_VIEW) {
             Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
         }
-        maybeShowManageEducation(false);
         mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
 
         // We're dragging an individual bubble, so set the magnetized object to the magnetized
         // bubble.
         mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
         mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener);
+
+        maybeShowManageEducation(false);
     }
 
     /** Called with the coordinates to which an individual bubble has been dragged. */
@@ -1841,17 +1857,16 @@
     }
 
     private void updatePointerPosition() {
-        Bubble expandedBubble = getExpandedBubble();
-        if (expandedBubble == null) {
+        if (mExpandedBubble == null) {
             return;
         }
-        int index = getBubbleIndex(expandedBubble);
+        int index = getBubbleIndex(mExpandedBubble);
         float bubbleLeftFromScreenLeft = mExpandedAnimationController.getBubbleLeft(index);
         float halfBubble = mBubbleSize / 2f;
         float bubbleCenter = bubbleLeftFromScreenLeft + halfBubble;
         // Padding might be adjusted for insets, so get it directly from the view
         bubbleCenter -= mExpandedViewContainer.getPaddingLeft();
-        expandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
+        mExpandedBubble.getExpandedView().setPointerPosition(bubbleCenter);
     }
 
     /**
@@ -1873,11 +1888,10 @@
      * is between 0 and the bubble count minus 1.
      */
     int getBubbleIndex(@Nullable BubbleViewProvider provider) {
-        if (provider == null || provider.getKey() == BubbleOverflow.KEY) {
+        if (provider == null) {
             return 0;
         }
-        Bubble b = (Bubble) provider;
-        return mBubbleContainer.indexOfChild(b.getIconView());
+        return mBubbleContainer.indexOfChild(provider.getIconView());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
index f04933a..ef84c73 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewProvider.java
@@ -41,4 +41,6 @@
     Path getDotPath();
 
     boolean showDot();
+
+    int getDisplayId();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index b81665c..86387f1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -68,9 +68,10 @@
     /**
      * Values to use for the default {@link SpringForce} provided to the physics animation layout.
      */
-    private static final int DEFAULT_STIFFNESS = 12000;
+    public static final int DEFAULT_STIFFNESS = 12000;
+    public static final float IME_ANIMATION_STIFFNESS = SpringForce.STIFFNESS_LOW;
     private static final int FLING_FOLLOW_STIFFNESS = 20000;
-    private static final float DEFAULT_BOUNCINESS = 0.9f;
+    public static final float DEFAULT_BOUNCINESS = 0.9f;
 
     /**
      * Friction applied to fling animations. Since the stack must land on one of the sides of the
@@ -118,8 +119,11 @@
     /** Whether or not the stack's start position has been set. */
     private boolean mStackMovedToStartPosition = false;
 
-    /** The most recent position in which the stack was resting on the edge of the screen. */
-    @Nullable private PointF mRestingStackPosition;
+    /**
+     * The stack's most recent position along the edge of the screen. This is saved when the last
+     * bubble is removed, so that the stack can be restored in its previous position.
+     */
+    private PointF mRestingStackPosition;
 
     /** The height of the most recently visible IME. */
     private float mImeHeight = 0f;
@@ -465,7 +469,6 @@
 
                 .addEndListener((animation, canceled, endValue, endVelocity) -> {
                     if (!canceled) {
-                        mRestingStackPosition = new PointF();
                         mRestingStackPosition.set(mStackPosition);
 
                         springFirstBubbleWithStackFollowing(property, spring, endVelocity,
@@ -501,8 +504,10 @@
     /**
      * Animates the stack either away from the newly visible IME, or back to its original position
      * due to the IME going away.
+     *
+     * @return The destination Y value of the stack due to the IME movement.
      */
-    public void animateForImeVisibility(boolean imeVisible) {
+    public float animateForImeVisibility(boolean imeVisible) {
         final float maxBubbleY = getAllowableStackPositionRegion().bottom;
         float destinationY = Float.MIN_VALUE;
 
@@ -523,12 +528,14 @@
             springFirstBubbleWithStackFollowing(
                     DynamicAnimation.TRANSLATION_Y,
                     getSpringForce(DynamicAnimation.TRANSLATION_Y, /* view */ null)
-                            .setStiffness(SpringForce.STIFFNESS_LOW),
+                            .setStiffness(IME_ANIMATION_STIFFNESS),
                     /* startVel */ 0f,
                     destinationY);
 
             notifyFloatingCoordinatorStackAnimatingTo(mStackPosition.x, destinationY);
         }
+
+        return destinationY;
     }
 
     /**
@@ -583,7 +590,7 @@
                             - mBubblePaddingTop
                             - (mImeHeight > Float.MIN_VALUE ? mImeHeight + mBubblePaddingTop : 0f)
                             - Math.max(
-                            insets.getSystemWindowInsetBottom(),
+                            insets.getStableInsetBottom(),
                             insets.getDisplayCutout() != null
                                     ? insets.getDisplayCutout().getSafeInsetBottom()
                                     : 0);
@@ -853,7 +860,12 @@
     public void setStackPosition(PointF pos) {
         Log.d(TAG, String.format("Setting position to (%f, %f).", pos.x, pos.y));
         mStackPosition.set(pos.x, pos.y);
-        mRestingStackPosition = mStackPosition;
+
+        if (mRestingStackPosition == null) {
+            mRestingStackPosition = new PointF();
+        }
+
+        mRestingStackPosition.set(mStackPosition);
 
         // If we're not the active controller, we don't want to physically move the bubble views.
         if (isActiveController()) {
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..ac97d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -25,8 +25,8 @@
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -54,7 +54,7 @@
             ShadeController shadeController,
             BubbleData data,
             ConfigurationController configurationController,
-            NotificationInterruptStateProvider interruptionStateProvider,
+            NotificationInterruptionStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
index 49a16d8..dec6007 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.controls
 
+import android.content.ComponentName
 import android.service.controls.Control
 
 data class ControlStatus(
     val control: Control,
+    val component: ComponentName,
     var favorite: Boolean,
     val removed: Boolean = false
-)
\ No newline at end of file
+)
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 50bd1ad..e5d36f9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -127,7 +127,7 @@
     internal val settingObserver = object : ContentObserver(null) {
         override fun onChange(
             selfChange: Boolean,
-            uris: MutableIterable<Uri>,
+            uris: Collection<Uri>,
             flags: Int,
             userId: Int
         ) {
@@ -238,7 +238,11 @@
                             }
                             val removed = findRemoved(favoritesForComponentKeys.toSet(), controls)
                             val controlsWithFavorite = controls.map {
-                                ControlStatus(it, it.controlId in favoritesForComponentKeys)
+                                ControlStatus(
+                                    it,
+                                    componentName,
+                                    it.controlId in favoritesForComponentKeys
+                                )
                             }
                             val loadData = createLoadDataObject(
                                 Favorites.getControlsForComponent(componentName)
@@ -253,17 +257,21 @@
                     }
 
                     override fun error(message: String) {
-                        val loadData = Favorites.getControlsForComponent(componentName).let {
-                            controls ->
+                        executor.execute {
+                            val loadData = Favorites.getControlsForComponent(componentName)
+                                .let { controls ->
                                 val keys = controls.map { it.controlId }
                                 createLoadDataObject(
-                                    controls.map { createRemovedStatus(componentName, it, false) },
-                                    keys,
-                                    true
+                                        controls.map {
+                                            createRemovedStatus(componentName, it, false)
+                                        },
+                                        keys,
+                                        true
                                 )
-                        }
+                            }
 
-                        dataCallback.accept(loadData)
+                            dataCallback.accept(loadData)
+                        }
                     }
                 }
         )
@@ -286,7 +294,7 @@
                 .setTitle(controlInfo.controlTitle)
                 .setDeviceType(controlInfo.deviceType)
                 .build()
-        return ControlStatus(control, true, setRemoved)
+        return ControlStatus(control, componentName, true, setRemoved)
     }
 
     private fun findRemoved(favoriteKeys: Set<String>, list: List<Control>): Set<String> {
@@ -485,10 +493,12 @@
                 updatedStructure
             } else { s }
 
-            structures.add(newStructure)
+            if (!newStructure.controls.isEmpty()) {
+                structures.add(newStructure)
+            }
         }
 
-        if (!replaced) {
+        if (!replaced && !updatedStructure.controls.isEmpty()) {
             structures.add(updatedStructure)
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
index c053517..01f9069 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
@@ -22,14 +22,20 @@
 import com.android.systemui.controls.controller.ControlInfo
 
 /**
- * This model is used to show all controls separated by zones.
+ * This model is used to show controls separated by zones.
  *
  * The model will sort the controls and zones in the following manner:
  *  * The zones will be sorted in a first seen basis
  *  * The controls in each zone will be sorted in a first seen basis.
  *
- * @property controls List of all controls as returned by loading
- * @property initialFavoriteIds sorted ids of favorite controls
+ *  The controls passed should belong to the same structure, as an instance of this model will be
+ *  created for each structure.
+ *
+ *  The list of favorite ids can contain ids for controls not passed to this model. Those will be
+ *  filtered out.
+ *
+ * @property controls List of controls as returned by loading
+ * @property initialFavoriteIds sorted ids of favorite controls.
  * @property noZoneString text to use as header for all controls that have blank or `null` zone.
  */
 class AllModel(
@@ -50,7 +56,10 @@
             }
         }
 
-    private val favoriteIds = initialFavoriteIds.toMutableList()
+    private val favoriteIds = run {
+        val ids = controls.mapTo(HashSet()) { it.control.controlId }
+        initialFavoriteIds.filter { it in ids }.toMutableList()
+    }
 
     override val elements: List<ElementWrapper> = createWrappers(controls)
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index c21f724..563c2f6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -16,8 +16,8 @@
 
 package com.android.systemui.controls.management
 
+import android.content.ComponentName
 import android.graphics.Rect
-import android.graphics.drawable.Icon
 import android.service.controls.DeviceTypes
 import android.view.LayoutInflater
 import android.view.View
@@ -42,7 +42,6 @@
  * @param onlyFavorites set to true to only display favorites instead of all controls
  */
 class ControlAdapter(
-    private val layoutInflater: LayoutInflater,
     private val elevation: Float
 ) : RecyclerView.Adapter<Holder>() {
 
@@ -60,6 +59,7 @@
     private var model: ControlsModel? = null
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
+        val layoutInflater = LayoutInflater.from(parent.context)
         return when (viewType) {
             TYPE_CONTROL -> {
                 ControlHolder(
@@ -147,7 +147,7 @@
     override fun bindData(wrapper: ElementWrapper) {
         wrapper as ControlWrapper
         val data = wrapper.controlStatus
-        val renderInfo = getRenderInfo(data.control.deviceType)
+        val renderInfo = getRenderInfo(data.component, data.control.deviceType)
         title.text = data.control.title
         subtitle.text = data.control.subtitle
         favorite.isChecked = data.favorite
@@ -160,16 +160,17 @@
     }
 
     private fun getRenderInfo(
+        component: ComponentName,
         @DeviceTypes.DeviceType deviceType: Int
     ): RenderInfo {
-        return RenderInfo.lookup(deviceType, true)
+        return RenderInfo.lookup(itemView.context, component, deviceType, true)
     }
 
     private fun applyRenderInfo(ri: RenderInfo) {
         val context = itemView.context
         val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
 
-        icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+        icon.setImageDrawable(ri.icon)
         icon.setImageTintList(fg)
     }
 }
@@ -191,4 +192,4 @@
             right = sideMargins
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 471f9d3..04715ab 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -19,20 +19,24 @@
 import android.app.Activity
 import android.content.ComponentName
 import android.content.Intent
+import android.graphics.drawable.Drawable
 import android.os.Bundle
-import android.view.LayoutInflater
+import android.text.TextUtils
 import android.view.View
 import android.view.ViewStub
 import android.widget.Button
+import android.widget.ImageView
 import android.widget.TextView
-import androidx.recyclerview.widget.GridLayoutManager
-import androidx.recyclerview.widget.RecyclerView
+import androidx.viewpager2.widget.ViewPager2
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastDispatcher
-import com.android.systemui.controls.controller.StructureInfo
+import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.controller.ControlsControllerImpl
+import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.PageIndicator
 import com.android.systemui.settings.CurrentUserTracker
+import java.text.Collator
 import java.util.concurrent.Executor
 import java.util.function.Consumer
 import javax.inject.Inject
@@ -40,6 +44,7 @@
 class ControlsFavoritingActivity @Inject constructor(
     @Main private val executor: Executor,
     private val controller: ControlsControllerImpl,
+    private val listingController: ControlsListingController,
     broadcastDispatcher: BroadcastDispatcher
 ) : Activity() {
 
@@ -48,12 +53,18 @@
         const val EXTRA_APP = "extra_app_label"
     }
 
-    private lateinit var recyclerViewAll: RecyclerView
-    private lateinit var adapterAll: ControlAdapter
-    private lateinit var statusText: TextView
-    private var model: ControlsModel? = null
     private var component: ComponentName? = null
-    private var structureName: CharSequence = ""
+    private var appName: CharSequence? = null
+
+    private lateinit var structurePager: ViewPager2
+    private lateinit var statusText: TextView
+    private lateinit var titleView: TextView
+    private lateinit var iconView: ImageView
+    private lateinit var iconFrame: View
+    private lateinit var pageIndicator: PageIndicator
+    private var listOfStructures = emptyList<StructureContainer>()
+
+    private lateinit var comparator: Comparator<StructureContainer>
 
     private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
         private val startingUser = controller.currentUserId
@@ -66,29 +77,117 @@
         }
     }
 
+    private val listingCallback = object : ControlsListingController.ControlsListingCallback {
+        private var icon: Drawable? = null
+
+        override fun onServicesUpdated(serviceInfos: List<ControlsServiceInfo>) {
+            val newIcon = serviceInfos.firstOrNull { it.componentName == component }?.loadIcon()
+            if (icon == newIcon) return
+            icon = newIcon
+            executor.execute {
+                if (icon != null) {
+                    iconView.setImageDrawable(icon)
+                }
+                iconFrame.visibility = if (icon != null) View.VISIBLE else View.GONE
+            }
+        }
+    }
+
     override fun onBackPressed() {
         finish()
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        val collator = Collator.getInstance(resources.configuration.locales[0])
+        comparator = compareBy(collator) { it.structureName }
+        appName = intent.getCharSequenceExtra(EXTRA_APP)
+        component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
+
+        bindViews()
+
+        setUpPager()
+
+        loadControls()
+
+        listingController.addCallback(listingCallback)
+
+        currentUserTracker.startTracking()
+    }
+
+    private fun loadControls() {
+        component?.let {
+            statusText.text = resources.getText(com.android.internal.R.string.loading)
+            val emptyZoneString = resources.getText(
+                    R.string.controls_favorite_other_zone_header)
+            controller.loadForComponent(it, Consumer { data ->
+                val allControls = data.allControls
+                val favoriteKeys = data.favoritesIds
+                val error = data.errorOnLoad
+                val controlsByStructure = allControls.groupBy { it.control.structure ?: "" }
+                listOfStructures = controlsByStructure.map {
+                    StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
+                }.sortedWith(comparator)
+                executor.execute {
+                    structurePager.adapter = StructureAdapter(listOfStructures)
+                    if (error) {
+                        statusText.text = resources.getText(R.string.controls_favorite_load_error)
+                    } else {
+                        statusText.visibility = View.GONE
+                    }
+                    pageIndicator.setNumPages(listOfStructures.size)
+                    pageIndicator.setLocation(0f)
+                    pageIndicator.visibility =
+                        if (listOfStructures.size > 1) View.VISIBLE else View.GONE
+                }
+            })
+        }
+    }
+
+    private fun setUpPager() {
+        structurePager.apply {
+            adapter = StructureAdapter(emptyList())
+            registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+                override fun onPageSelected(position: Int) {
+                    super.onPageSelected(position)
+                    val name = listOfStructures[position].structureName
+                    titleView.text = if (!TextUtils.isEmpty(name)) name else appName
+                }
+
+                override fun onPageScrolled(
+                    position: Int,
+                    positionOffset: Float,
+                    positionOffsetPixels: Int
+                ) {
+                    super.onPageScrolled(position, positionOffset, positionOffsetPixels)
+                    pageIndicator.setLocation(position + positionOffset)
+                }
+            })
+        }
+    }
+
+    private fun bindViews() {
         setContentView(R.layout.controls_management)
         requireViewById<ViewStub>(R.id.stub).apply {
             layoutResource = R.layout.controls_management_favorites
             inflate()
         }
 
-        val app = intent.getCharSequenceExtra(EXTRA_APP)
-        component = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)
         statusText = requireViewById(R.id.status_message)
+        pageIndicator = requireViewById(R.id.structure_page_indicator)
 
-        setUpRecyclerView()
-
-        requireViewById<TextView>(R.id.title).text = app?.let { it }
-                ?: resources.getText(R.string.controls_favorite_default_title)
+        titleView = requireViewById<TextView>(R.id.title).apply {
+            text = appName ?: resources.getText(R.string.controls_favorite_default_title)
+        }
         requireViewById<TextView>(R.id.subtitle).text =
                 resources.getText(R.string.controls_favorite_subtitle)
+        iconView = requireViewById(com.android.internal.R.id.icon)
+        iconFrame = requireViewById(R.id.icon_frame)
+        structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
+        bindButtons()
+    }
 
+    private fun bindButtons() {
         requireViewById<Button>(R.id.other_apps).apply {
             visibility = View.VISIBLE
             setOnClickListener {
@@ -98,64 +197,21 @@
 
         requireViewById<Button>(R.id.done).setOnClickListener {
             if (component == null) return@setOnClickListener
-            val favoritesForStorage = model?.favorites?.map {
-                it.build()
-            }
-            if (favoritesForStorage != null) {
-                controller.replaceFavoritesForStructure(StructureInfo(component!!, structureName,
+            listOfStructures.forEach {
+                val favoritesForStorage = it.model.favorites.map { it.build() }
+                controller.replaceFavoritesForStructure(StructureInfo(component!!, it.structureName,
                         favoritesForStorage))
-                finishAffinity()
             }
-        }
 
-        component?.let {
-            statusText.text = resources.getText(com.android.internal.R.string.loading)
-            controller.loadForComponent(it, Consumer { data ->
-                val allControls = data.allControls
-                val favoriteKeys = data.favoritesIds
-                val error = data.errorOnLoad
-                val structures = allControls.fold(hashSetOf<CharSequence>()) {
-                    s, c ->
-                        s.add(c.control.structure ?: "")
-                        s
-                }
-                // TODO add multi structure switching support
-                executor.execute {
-                    val emptyZoneString = resources.getText(
-                            R.string.controls_favorite_other_zone_header)
-                    val model = AllModel(allControls, favoriteKeys, emptyZoneString)
-                    adapterAll.changeModel(model)
-                    this.model = model
-                    if (error) {
-                        statusText.text = resources.getText(R.string.controls_favorite_load_error)
-                    } else {
-                        statusText.visibility = View.GONE
-                    }
-                }
-            })
-        }
-
-        currentUserTracker.startTracking()
-    }
-
-    private fun setUpRecyclerView() {
-        val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
-        val itemDecorator = MarginItemDecorator(margin, margin)
-        val layoutInflater = LayoutInflater.from(applicationContext)
-        val elevation = resources.getFloat(R.dimen.control_card_elevation)
-
-        adapterAll = ControlAdapter(layoutInflater, elevation)
-        recyclerViewAll = requireViewById<RecyclerView>(R.id.listAll).apply {
-            adapter = adapterAll
-            layoutManager = GridLayoutManager(applicationContext, 2).apply {
-                spanSizeLookup = adapterAll.spanSizeLookup
-            }
-            addItemDecoration(itemDecorator)
+            finishAffinity()
         }
     }
 
     override fun onDestroy() {
         currentUserTracker.stopTracking()
+        listingController.removeCallback(listingCallback)
         super.onDestroy()
     }
 }
+
+data class StructureContainer(val structureName: CharSequence, val model: ControlsModel)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 9b108cf..94487e5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -88,6 +88,8 @@
 
     init {
         serviceListing.addCallback(serviceListingCallback)
+        serviceListing.setListening(true)
+        serviceListing.reload()
     }
 
     override fun changeUser(newUser: UserHandle) {
@@ -95,11 +97,12 @@
             callbacks.clear()
             availableServices = emptyList()
             serviceListing.setListening(false)
-            serviceListing.removeCallback(serviceListingCallback)
             currentUserId = newUser.identifier
             val contextForUser = context.createContextAsUser(newUser, 0)
             serviceListing = serviceListingBuilder(contextForUser)
             serviceListing.addCallback(serviceListingCallback)
+            serviceListing.setListening(true)
+            serviceListing.reload()
         }
     }
 
@@ -118,12 +121,7 @@
         backgroundExecutor.execute {
             Log.d(TAG, "Subscribing callback")
             callbacks.add(listener)
-            if (callbacks.size == 1) {
-                serviceListing.setListening(true)
-                serviceListing.reload()
-            } else {
-                listener.onServicesUpdated(getCurrentServices())
-            }
+            listener.onServicesUpdated(getCurrentServices())
         }
     }
 
@@ -136,9 +134,6 @@
         backgroundExecutor.execute {
             Log.d(TAG, "Unsubscribing callback")
             callbacks.remove(listener)
-            if (callbacks.size == 0) {
-                serviceListing.setListening(false)
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
index 463632b..a7fc2ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
@@ -21,7 +21,6 @@
 import android.content.ComponentName
 import android.content.DialogInterface
 import android.content.Intent
-import android.graphics.drawable.Icon
 import android.os.Bundle
 import android.os.UserHandle
 import android.service.controls.Control
@@ -137,11 +136,10 @@
     }
 
     fun createDialog(label: CharSequence): Dialog {
-
-        val renderInfo = RenderInfo.lookup(control.deviceType, true)
+        val renderInfo = RenderInfo.lookup(this, component, control.deviceType, true)
         val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
             requireViewById<ImageView>(R.id.icon).apply {
-                setImageIcon(Icon.createWithResource(context, renderInfo.iconResourceId))
+                setImageDrawable(renderInfo.icon)
                 setImageTintList(
                         context.resources.getColorStateList(renderInfo.foreground, context.theme))
             }
@@ -176,4 +174,4 @@
         }
         finish()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
new file mode 100644
index 0000000..4289274
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.controls.management
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import com.android.systemui.qs.PageIndicator
+
+/**
+ * Page indicator for management screens.
+ *
+ * Adds RTL support to [PageIndicator]. To be used with [ViewPager2].
+ */
+class ManagementPageIndicator(
+    context: Context,
+    attrs: AttributeSet
+) : PageIndicator(context, attrs) {
+
+    override fun setLocation(location: Float) {
+        // Location doesn't know about RTL
+        if (layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+            val numPages = childCount
+            super.setLocation(numPages - 1 - location)
+        } else {
+            super.setLocation(location)
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
new file mode 100644
index 0000000..cb67454
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.controls.management
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
+
+class StructureAdapter(
+    private val models: List<StructureContainer>
+) : RecyclerView.Adapter<StructureAdapter.StructureHolder>() {
+
+    override fun onCreateViewHolder(parent: ViewGroup, p1: Int): StructureHolder {
+        val layoutInflater = LayoutInflater.from(parent.context)
+        return StructureHolder(
+            layoutInflater.inflate(R.layout.controls_structure_page, parent, false)
+        )
+    }
+
+    override fun getItemCount() = models.size
+
+    override fun onBindViewHolder(holder: StructureHolder, index: Int) {
+        holder.bind(models[index].model)
+    }
+
+    class StructureHolder(view: View) : RecyclerView.ViewHolder(view) {
+
+        private val recyclerView: RecyclerView
+        private val controlAdapter: ControlAdapter
+
+        init {
+            recyclerView = itemView.requireViewById<RecyclerView>(R.id.listAll)
+            val elevation = itemView.context.resources.getFloat(R.dimen.control_card_elevation)
+            controlAdapter = ControlAdapter(elevation)
+            setUpRecyclerView()
+        }
+
+        fun bind(model: ControlsModel) {
+            controlAdapter.changeModel(model)
+        }
+
+        private fun setUpRecyclerView() {
+            val margin = itemView.context.resources
+                .getDimensionPixelSize(R.dimen.controls_card_margin)
+            val itemDecorator = MarginItemDecorator(margin, margin)
+
+            recyclerView.apply {
+                this.adapter = controlAdapter
+                layoutManager = GridLayoutManager(recyclerView.context, 2).apply {
+                    spanSizeLookup = controlAdapter.spanSizeLookup
+                }
+                addItemDecoration(itemDecorator)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
new file mode 100644
index 0000000..2494fd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.controls.ui
+
+import android.app.AlertDialog
+import android.app.Dialog
+import android.content.DialogInterface
+import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
+import android.service.controls.actions.ControlAction
+import android.service.controls.actions.FloatAction
+import android.service.controls.actions.ModeAction
+import android.text.InputType
+import android.util.Log
+import android.view.WindowManager
+import android.widget.CheckBox
+import android.widget.EditText
+
+import com.android.systemui.R
+
+/**
+ * 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}.
+ */
+object ChallengeDialogs {
+
+    fun createPinDialog(cvh: ControlViewHolder): 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 {
+            setTitle(R.string.controls_pin_verify)
+            setView(R.layout.controls_dialog_pin)
+            setPositiveButton(
+                android.R.string.ok,
+                DialogInterface.OnClickListener { dialog, _ ->
+                    if (dialog is Dialog) {
+                        dialog.requireViewById<EditText>(R.id.controls_pin_input)
+                        val pin = dialog.requireViewById<EditText>(R.id.controls_pin_input)
+                            .getText().toString()
+                        cvh.action(addChallengeValue(lastAction, pin))
+                        dialog.dismiss()
+                    }
+            })
+            setNegativeButton(
+                android.R.string.cancel,
+                DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() }
+            )
+        }
+        return builder.create().apply {
+            getWindow().apply {
+                setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+                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)
+                    }
+                }
+                editText.requestFocus()
+            })
+        }
+    }
+
+    private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction {
+        val id = action.getTemplateId()
+        return when (action) {
+            is BooleanAction -> BooleanAction(id, action.getNewState(), challengeValue)
+            is FloatAction -> FloatAction(id, action.getNewValue(), challengeValue)
+            is CommandAction -> CommandAction(id, challengeValue)
+            is ModeAction -> ModeAction(id, action.getNewMode(), challengeValue)
+            else -> throw IllegalStateException("'action' is not a known type: $action")
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index eb84a8b..680d006 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -20,6 +20,7 @@
 import android.content.Intent
 import android.provider.Settings
 import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
 import android.util.Log
 import android.view.HapticFeedbackConstants
 
@@ -36,6 +37,10 @@
         cvh.clipLayer.setLevel(nextLevel)
     }
 
+    fun touch(cvh: ControlViewHolder, templateId: String) {
+        cvh.action(CommandAction(templateId))
+    }
+
     fun longPress(cvh: ControlViewHolder) {
         // Long press snould only be called when there is valid control state, otherwise ignore
         cvh.cws.control?.let {
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 d56428d..fc5663f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -19,15 +19,14 @@
 import android.content.Context
 import android.graphics.BlendMode
 import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.Icon
 import android.graphics.drawable.LayerDrawable
 import android.service.controls.Control
 import android.service.controls.actions.ControlAction
 import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.StatelessTemplate
 import android.service.controls.templates.TemperatureControlTemplate
 import android.service.controls.templates.ToggleRangeTemplate
 import android.service.controls.templates.ToggleTemplate
-import android.util.Log
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
@@ -57,6 +56,7 @@
     lateinit var cws: ControlWithState
     var cancelUpdate: Runnable? = null
     var behavior: Behavior? = null
+    var lastAction: ControlAction? = null
 
     init {
         val ld = layout.getBackground() as LayerDrawable
@@ -98,7 +98,6 @@
 
     fun actionResponse(@ControlAction.ResponseResult response: Int) {
         // TODO: b/150931809 - handle response codes
-        Log.d(ControlsUiController.TAG, "Received response code: $response")
     }
 
     fun setTransientStatus(tempStatus: String) {
@@ -115,6 +114,7 @@
     }
 
     fun action(action: ControlAction) {
+        lastAction = action
         controlsController.action(cws.componentName, cws.ci, action)
     }
 
@@ -122,19 +122,25 @@
         return when {
             status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
             template is ToggleTemplate -> ToggleBehavior::class
+            template is StatelessTemplate -> TouchBehavior::class
             template is ToggleRangeTemplate -> ToggleRangeBehavior::class
             template is TemperatureControlTemplate -> TemperatureControlBehavior::class
             else -> DefaultBehavior::class
         }
     }
 
-    internal fun applyRenderInfo(ri: RenderInfo) {
+    internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
+        setEnabled(enabled)
+
+        val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
+        val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
+
         val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
         val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
         status.setTextColor(fg)
         statusExtra.setTextColor(fg)
 
-        icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+        icon.setImageDrawable(ri.icon)
         icon.setImageTintList(fg)
 
         clipLayer.getDrawable().apply {
@@ -143,7 +149,7 @@
         }
     }
 
-    fun setEnabled(enabled: Boolean) {
+    private fun setEnabled(enabled: Boolean) {
         status.setEnabled(enabled)
         icon.setEnabled(enabled)
     }
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 eaf57ff..bde966c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -16,18 +16,15 @@
 
 package com.android.systemui.controls.ui
 
-import android.accounts.Account
-import android.accounts.AccountManager
+import android.app.Dialog
 import android.content.ComponentName
 import android.content.Context
 import android.content.Intent
-import android.content.ServiceConnection
 import android.content.SharedPreferences
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
-import android.os.IBinder
 import android.service.controls.Control
-import android.service.controls.TokenProvider
+import android.service.controls.actions.ControlAction
 import android.util.Log
 import android.view.ContextThemeWrapper
 import android.view.LayoutInflater
@@ -49,8 +46,8 @@
 import com.android.systemui.controls.management.ControlsProviderSelectorActivity
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.R
 import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.R
 
 import dagger.Lazy
 
@@ -59,68 +56,6 @@
 import javax.inject.Inject
 import javax.inject.Singleton
 
-// TEMP CODE for MOCK
-private const val TOKEN = "https://www.googleapis.com/auth/assistant"
-private const val SCOPE = "oauth2:" + TOKEN
-private var tokenProviderConnection: TokenProviderConnection? = null
-class TokenProviderConnection(
-    val cc: ControlsController,
-    val context: Context,
-    val structure: StructureInfo?
-) : ServiceConnection {
-    private var mTokenProvider: TokenProvider? = null
-
-    override fun onServiceConnected(cName: ComponentName, binder: IBinder) {
-        Thread({
-            Log.i(ControlsUiController.TAG, "TokenProviderConnection connected")
-            mTokenProvider = TokenProvider.Stub.asInterface(binder)
-
-            val mLastAccountName = mTokenProvider?.getAccountName()
-
-            if (mLastAccountName == null || mLastAccountName.isEmpty()) {
-                Log.e(ControlsUiController.TAG, "NO ACCOUNT IS SET. Open HomeMock app")
-            } else {
-                mTokenProvider?.setAuthToken(getAuthToken(mLastAccountName))
-                structure?.let {
-                    cc.subscribeToFavorites(it)
-                }
-            }
-        }, "TokenProviderThread").start()
-    }
-
-    override fun onServiceDisconnected(cName: ComponentName) {
-        mTokenProvider = null
-    }
-
-    fun getAuthToken(accountName: String): String? {
-        val am = AccountManager.get(context)
-        val accounts = am.getAccountsByType("com.google")
-        if (accounts == null || accounts.size == 0) {
-            Log.w(ControlsUiController.TAG, "No com.google accounts found")
-            return null
-        }
-
-        var account: Account? = null
-        for (a in accounts) {
-            if (a.name.equals(accountName)) {
-                account = a
-                break
-            }
-        }
-
-        if (account == null) {
-            account = accounts[0]
-        }
-
-        try {
-            return am.blockingGetAuthToken(account!!, SCOPE, true)
-        } catch (e: Throwable) {
-            Log.e(ControlsUiController.TAG, "Error getting auth token", e)
-            return null
-        }
-    }
-}
-
 private data class ControlKey(val componentName: ComponentName, val controlId: String)
 
 @Singleton
@@ -152,7 +87,7 @@
     private lateinit var parent: ViewGroup
     private lateinit var lastItems: List<SelectionItem>
     private var popup: ListPopupWindow? = null
-
+    private var activeDialog: Dialog? = null
     private val addControlsItem: SelectionItem
 
     init {
@@ -213,21 +148,10 @@
                 ControlKey(selectedStructure.componentName, it.ci.controlId)
             }
             listingCallback = createCallback(::showControlsView)
+            controlsController.get().subscribeToFavorites(selectedStructure)
         }
 
         controlsListingController.get().addCallback(listingCallback)
-
-        // Temp code to pass auth
-        tokenProviderConnection = TokenProviderConnection(controlsController.get(), context,
-                selectedStructure)
-
-        val serviceIntent = Intent()
-        serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock",
-                "com.android.systemui.home.mock.AuthService"))
-        if (!context.bindService(serviceIntent, tokenProviderConnection!!,
-                Context.BIND_AUTO_CREATE)) {
-            controlsController.get().subscribeToFavorites(selectedStructure)
-        }
     }
 
     private fun showInitialSetupView(items: List<SelectionItem>) {
@@ -264,36 +188,23 @@
         parent.removeAllViews()
         controlViewsById.clear()
 
-        val inflater = LayoutInflater.from(context)
-        inflater.inflate(R.layout.controls_with_favorites, parent, true)
+        createListView()
+        createDropDown(items)
+    }
 
-        val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
-        var lastRow: ViewGroup = createRow(inflater, listView)
-        selectedStructure.controls.forEach {
-            if (lastRow.getChildCount() == 2) {
-                lastRow = createRow(inflater, listView)
-            }
-            val item = inflater.inflate(
-                R.layout.controls_base_item, lastRow, false) as ViewGroup
-            lastRow.addView(item)
-            val cvh = ControlViewHolder(item, controlsController.get(), uiExecutor, bgExecutor)
-            val key = ControlKey(selectedStructure.componentName, it.controlId)
-            cvh.bindData(controlsById.getValue(key))
-            controlViewsById.put(key, cvh)
-        }
-
-        // add spacer if necessary to keep control size consistent
-        if ((selectedStructure.controls.size % 2) == 1) {
-            lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+    private fun createDropDown(items: List<SelectionItem>) {
+        items.forEach {
+            RenderInfo.registerComponentIcon(it.componentName, it.icon)
         }
 
         val itemsByComponent = items.associateBy { it.componentName }
-        var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
-            val listItems = allStructures.mapNotNull {
-                itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
-            }
+        val itemsWithStructure = allStructures.mapNotNull {
+            itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
+        }
+        val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
 
-            addAll(listItems + addControlsItem)
+        var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
+            addAll(itemsWithStructure + addControlsItem)
         }
 
         /*
@@ -301,16 +212,15 @@
          * for this dialog. Use a textView with the ListPopupWindow to achieve
          * a similar effect
          */
-        val item = adapter.findSelectionItem(selectedStructure) ?: adapter.getItem(0)
         parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
-            setText(item.getTitle())
+            setText(selectionItem.getTitle())
             // override the default color on the dropdown drawable
             (getBackground() as LayerDrawable).getDrawable(1)
                 .setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
         }
         parent.requireViewById<ImageView>(R.id.app_icon).apply {
-            setContentDescription(item.getTitle())
-            setImageDrawable(item.icon)
+            setContentDescription(selectionItem.getTitle())
+            setImageDrawable(selectionItem.icon)
         }
         val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
         anchor.setOnClickListener(object : View.OnClickListener {
@@ -348,6 +258,36 @@
         })
     }
 
+    private fun createListView() {
+        val inflater = LayoutInflater.from(context)
+        inflater.inflate(R.layout.controls_with_favorites, parent, true)
+
+        val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
+        var lastRow: ViewGroup = createRow(inflater, listView)
+        selectedStructure.controls.forEach {
+            if (lastRow.getChildCount() == 2) {
+                lastRow = createRow(inflater, listView)
+            }
+            val baseLayout = inflater.inflate(
+                R.layout.controls_base_item, lastRow, false) as ViewGroup
+            lastRow.addView(baseLayout)
+            val cvh = ControlViewHolder(
+                baseLayout,
+                controlsController.get(),
+                uiExecutor,
+                bgExecutor
+            )
+            val key = ControlKey(selectedStructure.componentName, it.controlId)
+            cvh.bindData(controlsById.getValue(key))
+            controlViewsById.put(key, cvh)
+        }
+
+        // add spacer if necessary to keep control size consistent
+        if ((selectedStructure.controls.size % 2) == 1) {
+            lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+        }
+    }
+
     private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
         if (structures.isEmpty()) return EMPTY_STRUCTURE
 
@@ -388,15 +328,16 @@
     override fun hide() {
         Log.d(ControlsUiController.TAG, "hide()")
         popup?.dismiss()
+        activeDialog?.dismiss()
 
         controlsController.get().unsubscribe()
-        context.unbindService(tokenProviderConnection)
-        tokenProviderConnection = null
 
         parent.removeAllViews()
         controlsById.clear()
         controlViewsById.clear()
         controlsListingController.get().removeCallback(listingCallback)
+
+        RenderInfo.clearCache()
     }
 
     override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
@@ -418,7 +359,15 @@
     override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
         val key = ControlKey(componentName, controlId)
         uiExecutor.execute {
-            controlViewsById.get(key)?.actionResponse(response)
+            controlViewsById.get(key)?.let { cvh ->
+                when (response) {
+                    ControlAction.RESPONSE_CHALLENGE_PIN -> {
+                        activeDialog = ChallengeDialogs.createPinDialog(cvh)
+                        activeDialog?.show()
+                    }
+                    else -> cvh.actionResponse(response)
+                }
+            }
         }
     }
 
@@ -427,6 +376,11 @@
         listView.addView(row)
         return row
     }
+
+    private fun findSelectionItem(si: StructureInfo, items: List<SelectionItem>): SelectionItem? =
+        items.firstOrNull {
+            it.componentName == si.componentName && it.structure == si.structure
+        }
 }
 
 private data class SelectionItem(
@@ -457,17 +411,4 @@
         }
         return view
     }
-
-    fun findSelectionItem(si: StructureInfo): SelectionItem? {
-        var i = 0
-        while (i < getCount()) {
-            val item = getItem(i)
-            if (item.componentName == si.componentName &&
-                item.structure == si.structure) {
-                return item
-            }
-            i++
-        }
-        return null
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
index 1747929..e850a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
@@ -25,7 +25,6 @@
 
     override fun bind(cws: ControlWithState) {
         cvh.status.setText(cws.control?.getStatusText() ?: "")
-        cvh.setEnabled(false)
-        cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+        cvh.applyRenderInfo(false)
     }
 }
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 da52c6f..56267be 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -16,8 +16,14 @@
 
 package com.android.systemui.controls.ui
 
+import android.annotation.MainThread
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.drawable.Drawable
 import android.service.controls.DeviceTypes
 import android.service.controls.templates.TemperatureControlTemplate
+import android.util.ArrayMap
+import android.util.SparseArray
 
 import com.android.systemui.R
 
@@ -31,18 +37,54 @@
     }
 }
 
-data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) {
+data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
 
     companion object {
-        fun lookup(deviceType: Int, enabled: Boolean): RenderInfo {
-            val iconState = deviceIconMap.getValue(deviceType)
+        const val APP_ICON_ID = -1
+        private val iconMap = SparseArray<Drawable>()
+        private val appIconMap = ArrayMap<ComponentName, Drawable>()
+
+        @MainThread
+        fun lookup(
+            context: Context,
+            componentName: ComponentName,
+            deviceType: Int,
+            enabled: Boolean,
+            offset: Int = 0
+        ): RenderInfo {
             val (fg, bg) = deviceColorMap.getValue(deviceType)
-            return RenderInfo(iconState[enabled], fg, bg)
+
+            val iconKey = if (offset > 0) {
+                deviceType * BUCKET_SIZE + offset
+            } else deviceType
+
+            val iconState = deviceIconMap.getValue(iconKey)
+            val resourceId = iconState[enabled]
+            var icon: Drawable? = null
+            if (resourceId == APP_ICON_ID) {
+                icon = appIconMap.get(componentName)
+                if (icon == null) {
+                    icon = context.resources
+                        .getDrawable(R.drawable.ic_device_unknown_gm2_24px, null)
+                    appIconMap.put(componentName, icon)
+                }
+            } else {
+                icon = iconMap.get(resourceId)
+                if (icon == null) {
+                    icon = context.resources.getDrawable(resourceId, null)
+                    iconMap.put(resourceId, icon)
+                }
+            }
+            return RenderInfo(icon!!, fg, bg)
         }
 
-        fun lookup(deviceType: Int, offset: Int, enabled: Boolean): RenderInfo {
-            val key = deviceType * BUCKET_SIZE + offset
-            return lookup(key, enabled)
+        fun registerComponentIcon(componentName: ComponentName, icon: Drawable) {
+            appIconMap.put(componentName, icon)
+        }
+
+        fun clearCache() {
+            iconMap.clear()
+            appIconMap.clear()
         }
     }
 }
@@ -116,6 +158,10 @@
     DeviceTypes.TYPE_MOP to IconState(
         R.drawable.ic_vacuum_gm2_24px,
         R.drawable.ic_vacuum_gm2_24px
+    ),
+    DeviceTypes.TYPE_ROUTINE to IconState(
+        RenderInfo.APP_ICON_ID,
+        RenderInfo.APP_ICON_ID
     )
 ).withDefault {
     IconState(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index 239d2e5..15c1dab 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -47,10 +47,7 @@
 
         val activeMode = template.getCurrentActiveMode()
         val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
-        val deviceType = control.getDeviceType()
-
         clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
-        cvh.setEnabled(enabled)
-        cvh.applyRenderInfo(RenderInfo.lookup(deviceType, activeMode, enabled))
+        cvh.applyRenderInfo(enabled, activeMode)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
index d306d7c..a3368ef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
@@ -34,7 +34,7 @@
 
     override fun initialize(cvh: ControlViewHolder) {
         this.cvh = cvh
-        cvh.setEnabled(false)
+        cvh.applyRenderInfo(false)
 
         cvh.layout.setOnClickListener(View.OnClickListener() {
             ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
@@ -51,10 +51,7 @@
         clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
 
         val checked = template.isChecked()
-        val deviceType = control.getDeviceType()
-
         clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
-        cvh.setEnabled(checked)
-        cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+        cvh.applyRenderInfo(checked)
     }
 }
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 cca56c2..6595b55 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -56,7 +56,7 @@
         status = cvh.status
         context = status.getContext()
 
-        cvh.setEnabled(false)
+        cvh.applyRenderInfo(false)
 
         val gestureListener = ToggleRangeGestureListener(cvh.layout)
         val gestureDetector = GestureDetector(context, gestureListener)
@@ -89,14 +89,11 @@
         rangeTemplate = template.getRange()
 
         val checked = template.isChecked()
-        val deviceType = control.getDeviceType()
-
         val currentRatio = rangeTemplate.getCurrentValue() /
                 (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
         updateRange(currentRatio, checked)
 
-        cvh.setEnabled(checked)
-        cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+        cvh.applyRenderInfo(checked)
     }
 
     fun beginUpdateRange() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
new file mode 100644
index 0000000..d64a5f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.controls.ui
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.view.View
+import android.service.controls.Control
+import android.service.controls.templates.StatelessTemplate
+
+import com.android.systemui.R
+import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
+
+/**
+ * Supports touch events, but has no notion of state as the {@link ToggleBehavior} does. Must be
+ * used with {@link StatelessTemplate}.
+ */
+class TouchBehavior : Behavior {
+    lateinit var clipLayer: Drawable
+    lateinit var template: StatelessTemplate
+    lateinit var control: Control
+    lateinit var cvh: ControlViewHolder
+
+    override fun initialize(cvh: ControlViewHolder) {
+        this.cvh = cvh
+        cvh.applyRenderInfo(false)
+
+        cvh.layout.setOnClickListener(View.OnClickListener() {
+            ControlActionCoordinator.touch(cvh, template.getTemplateId())
+        })
+    }
+
+    override fun bind(cws: ControlWithState) {
+        this.control = cws.control!!
+        cvh.status.setText(control.getStatusText())
+        template = control.getControlTemplate() as StatelessTemplate
+
+        val ld = cvh.layout.getBackground() as LayerDrawable
+        clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
+        clipLayer.setLevel(MIN_LEVEL)
+
+        cvh.applyRenderInfo(false)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
index 1f33b85..c357249 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
@@ -25,7 +25,6 @@
 
     override fun bind(cws: ControlWithState) {
         cvh.status.setText(cvh.context.getString(com.android.internal.R.string.loading))
-        cvh.setEnabled(false)
-        cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+        cvh.applyRenderInfo(false)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 2877ed0..5b3d5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -44,8 +44,6 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
 import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
 import com.android.systemui.statusbar.policy.CastController;
@@ -179,12 +177,6 @@
     /**
      */
     @Binds
-    public abstract BatteryController provideBatteryController(
-            BatteryControllerImpl controllerImpl);
-
-    /**
-     */
-    @Binds
     public abstract ManagedProfileController provideManagedProfileController(
             ManagedProfileControllerImpl controllerImpl);
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 3a4b273..6c502d2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -90,7 +90,7 @@
 
     /** */
     @Provides
-    public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
+    public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
         return new AmbientDisplayConfiguration(context);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index b4e5125..956b4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -43,6 +43,8 @@
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.ShadeControllerImpl;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -78,6 +80,11 @@
             NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
 
     @Binds
+    @Singleton
+    public abstract BatteryController provideBatteryController(
+            BatteryControllerImpl controllerImpl);
+
+    @Binds
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index c28a719..700a861 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -49,6 +49,7 @@
 import com.android.systemui.util.wakelock.WakeLock;
 
 import java.io.PrintWriter;
+import java.util.Collection;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -261,7 +262,7 @@
 
     private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
-        public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+        public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
             if (userId != ActivityManager.getCurrentUser()) {
                 return;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 24f505d..786ad2c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1574,7 +1574,6 @@
 
         private ControlsUiController mControlsUiController;
         private ViewGroup mControlsView;
-        private ViewGroup mContainerView;
 
         ActionsDialog(Context context, MyAdapter adapter,
                 GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
@@ -1671,7 +1670,6 @@
             mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls);
             mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
             mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
-            ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss());
             mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
                 @Override
                 public boolean dispatchPopulateAccessibilityEvent(
@@ -1684,6 +1682,15 @@
             mGlobalActionsLayout.setRotationListener(this::onRotate);
             mGlobalActionsLayout.setAdapter(mAdapter);
 
+            View globalActionsParent = (View) mGlobalActionsLayout.getParent();
+            globalActionsParent.setOnClickListener(v -> dismiss());
+
+            // add fall-through dismiss handling to root view
+            View rootView = findViewById(com.android.systemui.R.id.global_actions_grid_root);
+            if (rootView != null) {
+                rootView.setOnClickListener(v -> dismiss());
+            }
+
             if (shouldUsePanel()) {
                 initializePanel();
             }
@@ -1692,14 +1699,6 @@
                 mScrimAlpha = ScrimController.BUSY_SCRIM_ALPHA;
             }
             getWindow().setBackgroundDrawable(mBackgroundDrawable);
-
-            if (mControlsView != null) {
-                mContainerView = findViewById(com.android.systemui.R.id.global_actions_container);
-                mContainerView.setOnTouchListener((v, e) -> {
-                    dismiss();
-                    return true;
-                });
-            }
         }
 
         private void fixNavBarClipping() {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
new file mode 100644
index 0000000..622fa65
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/MinHeightScrollView.java
@@ -0,0 +1,43 @@
+/*
+ * 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.globalactions;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ScrollView;
+
+/**
+ * When measured, this view sets the minimum height of its first child to be equal to its own
+ * target height.
+ *
+ * This ensures fall-through click handlers can be placed on this view's child component.
+ */
+public class MinHeightScrollView extends ScrollView {
+    public MinHeightScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        View firstChild = getChildAt(0);
+        if (firstChild != null) {
+            firstChild.setMinimumHeight(MeasureSpec.getSize(heightMeasureSpec));
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 3933af0..00b977e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -33,10 +33,10 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.DisplayInfo;
 import android.view.ITaskOrganizer;
 import android.view.IWindowContainer;
 import android.view.SurfaceControl;
@@ -47,7 +47,9 @@
 import com.android.systemui.pip.phone.PipUpdateThread;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.function.Consumer;
 
@@ -76,9 +78,9 @@
     private final PipBoundsHandler mPipBoundsHandler;
     private final PipAnimationController mPipAnimationController;
     private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
-    private final Rect mDisplayBounds = new Rect();
     private final Rect mLastReportedBounds = new Rect();
     private final int mCornerRadius;
+    private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
 
     // These callbacks are called on the update thread
     private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -201,29 +203,6 @@
     }
 
     /**
-     * Updates the display dimension with given {@link DisplayInfo}
-     */
-    @SuppressWarnings("unchecked")
-    public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-        final Rect newDisplayBounds = new Rect(0, 0,
-                displayInfo.logicalWidth, displayInfo.logicalHeight);
-        if (!mDisplayBounds.equals(newDisplayBounds)) {
-            // Updates the exiting PiP animation in case the screen rotation changes in the middle.
-            // It's a legit case that PiP window is in portrait mode on home screen and
-            // the application requests landscape once back to fullscreen mode.
-            final PipAnimationController.PipTransitionAnimator animator =
-                    mPipAnimationController.getCurrentAnimator();
-            if (animator != null
-                    && animator.getAnimationType() == ANIM_TYPE_BOUNDS
-                    && animator.getDestinationBounds().equals(mDisplayBounds)) {
-                animator.updateEndValue(newDisplayBounds);
-                animator.setDestinationBounds(newDisplayBounds);
-            }
-        }
-        mDisplayBounds.set(newDisplayBounds);
-    }
-
-    /**
      * Callback to issue the final {@link WindowContainerTransaction} on end of movements.
      * @param destinationBounds the final bounds.
      */
@@ -252,8 +231,9 @@
         } catch (RemoteException e) {
             throw new RuntimeException("Unable to get leash", e);
         }
+        final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+        mBoundsToRestore.put(mToken.asBinder(), currentBounds);
         if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
-            final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
             scheduleAnimateResizePip(currentBounds, destinationBounds,
                     TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
         } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -271,13 +251,15 @@
     }
 
     @Override
-    public void taskVanished(IWindowContainer token) {
+    public void taskVanished(ActivityManager.RunningTaskInfo info) {
+        IWindowContainer token = info.token;
         Objects.requireNonNull(token, "Requires valid IWindowContainer");
         if (token.asBinder() != mToken.asBinder()) {
             Log.wtf(TAG, "Unrecognized token: " + token);
             return;
         }
-        scheduleAnimateResizePip(mLastReportedBounds, mDisplayBounds,
+        final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
+        scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
                 TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
         mInPip = false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 4b97d13..1fdf92e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -128,7 +128,12 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                boolean homeTaskVisible, boolean clearedTask) {
+            if (task.configuration.windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_PINNED) {
+                return;
+            }
             mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
         }
     };
@@ -185,10 +190,7 @@
 
         @Override
         public void onDisplayInfoChanged(DisplayInfo displayInfo) {
-            mHandler.post(() -> {
-                mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
-                mPipTaskOrganizer.onDisplayInfoChanged(displayInfo);
-            });
+            mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
         }
 
         @Override
@@ -352,7 +354,6 @@
         mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
                 animatingBounds, fromImeAdjustment, fromShelfAdjustment,
                 mTmpDisplayInfo.rotation);
-        mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo);
     }
 
     public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index a5e9dbc..0c5a4d7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -680,7 +680,12 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+        public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+                boolean clearedTask) {
+            if (task.configuration.windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_PINNED) {
+                return;
+            }
             if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
 
             // If PIPed activity is launched again by Launcher or intent, make it fullscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index f3e2f10..5bf44c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -20,6 +20,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.trust.TrustManager;
@@ -37,6 +39,7 @@
 import com.android.systemui.R;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.phone.StatusBar;
 
@@ -63,6 +66,21 @@
     private TrustManager mTrustManager;
     private OverviewProxyService mOverviewProxyService;
 
+    private TaskStackChangeListener mListener = new TaskStackChangeListener() {
+        @Override
+        public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+                boolean homeTaskVisible, boolean clearedTask) {
+            if (task.configuration.windowConfiguration.getWindowingMode()
+                    != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+                return;
+            }
+
+            if (homeTaskVisible) {
+                showRecentApps(false /* triggeredFromAltTab */);
+            }
+        }
+    };
+
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
     public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
@@ -77,6 +95,7 @@
         mHandler = new Handler();
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mListener);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index c6eecf26..fb68153 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -129,217 +129,213 @@
                 }
             };
 
-    private DisplayImeController.ImePositionProcessor mImePositionProcessor =
-            new DisplayImeController.ImePositionProcessor() {
-                /**
-                 * These are the y positions of the top of the IME surface when it is hidden and
-                 * when it is shown respectively. These are NOT necessarily the top of the visible
-                 * IME itself.
-                 */
-                private int mHiddenTop = 0;
-                private int mShownTop = 0;
+    private class DividerImeController implements DisplayImeController.ImePositionProcessor {
+        /**
+         * These are the y positions of the top of the IME surface when it is hidden and when it is
+         * shown respectively. These are NOT necessarily the top of the visible IME itself.
+         */
+        private int mHiddenTop = 0;
+        private int mShownTop = 0;
 
-                // The following are target states (what we are curretly animating towards).
-                /**
-                 * {@code true} if, at the end of the animation, the split task positions should be
-                 * adjusted by height of the IME. This happens when the secondary split is the IME
-                 * target.
-                 */
-                private boolean mTargetAdjusted = false;
-                /**
-                 * {@code true} if, at the end of the animation, the IME should be shown/visible
-                 * regardless of what has focus.
-                 */
-                private boolean mTargetShown = false;
+        // The following are target states (what we are curretly animating towards).
+        /**
+         * {@code true} if, at the end of the animation, the split task positions should be
+         * adjusted by height of the IME. This happens when the secondary split is the IME target.
+         */
+        private boolean mTargetAdjusted = false;
+        /**
+         * {@code true} if, at the end of the animation, the IME should be shown/visible
+         * regardless of what has focus.
+         */
+        private boolean mTargetShown = false;
 
-                // The following are the current (most recent) states set during animation
-                /**
-                 * {@code true} if the secondary split has IME focus.
-                 */
-                private boolean mSecondaryHasFocus = false;
-                /** The dimming currently applied to the primary/secondary splits. */
-                private float mLastPrimaryDim = 0.f;
-                private float mLastSecondaryDim = 0.f;
-                /** The most recent y position of the top of the IME surface */
-                private int mLastAdjustTop = -1;
+        // The following are the current (most recent) states set during animation
+        /** {@code true} if the secondary split has IME focus. */
+        private boolean mSecondaryHasFocus = false;
+        /** The dimming currently applied to the primary/secondary splits. */
+        private float mLastPrimaryDim = 0.f;
+        private float mLastSecondaryDim = 0.f;
+        /** The most recent y position of the top of the IME surface */
+        private int mLastAdjustTop = -1;
 
-                // The following are states reached last time an animation fully completed.
-                /** {@code true} if the IME was shown/visible by the last-completed animation. */
-                private boolean mImeWasShown = false;
-                /**
-                 * {@code true} if the split positions were adjusted by the last-completed
-                 * animation.
-                 */
-                private boolean mAdjusted = false;
+        // The following are states reached last time an animation fully completed.
+        /** {@code true} if the IME was shown/visible by the last-completed animation. */
+        private boolean mImeWasShown = false;
+        /** {@code true} if the split positions were adjusted by the last-completed animation. */
+        private boolean mAdjusted = false;
 
-                /**
-                 * When some aspect of split-screen needs to animate independent from the IME,
-                 * this will be non-null and control split animation.
-                 */
-                @Nullable
-                private ValueAnimator mAnimation = null;
+        /**
+         * When some aspect of split-screen needs to animate independent from the IME,
+         * this will be non-null and control split animation.
+         */
+        @Nullable
+        private ValueAnimator mAnimation = null;
 
-                private boolean getSecondaryHasFocus(int displayId) {
-                    try {
-                        IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
-                                .getImeTarget(displayId);
-                        return imeSplit != null
-                                && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed to get IME target", e);
-                    }
-                    return false;
-                }
+        private boolean getSecondaryHasFocus(int displayId) {
+            try {
+                IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
+                        .getImeTarget(displayId);
+                return imeSplit != null
+                        && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to get IME target", e);
+            }
+            return false;
+        }
 
+        @Override
+        public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+                boolean imeShouldShow, SurfaceControl.Transaction t) {
+            mSecondaryHasFocus = getSecondaryHasFocus(displayId);
+            mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
+                    && !mSplitLayout.mDisplayLayout.isLandscape();
+            mHiddenTop = hiddenTop;
+            mShownTop = shownTop;
+            mTargetShown = imeShouldShow;
+            if (mLastAdjustTop < 0) {
+                mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
+            }
+            if (mAnimation != null || (mImeWasShown && imeShouldShow
+                    && mTargetAdjusted != mAdjusted)) {
+                // We need to animate adjustment independently of the IME position, so
+                // start our own animation to drive adjustment. This happens when a
+                // different split's editor has gained focus while the IME is still visible.
+                startAsyncAnimation();
+            }
+            updateImeAdjustState();
+        }
+
+        private void updateImeAdjustState() {
+            // Reposition the server's secondary split position so that it evaluates
+            // insets properly.
+            WindowContainerTransaction wct = new WindowContainerTransaction();
+            if (mTargetAdjusted) {
+                mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
+                wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+                // "Freeze" the configuration size so that the app doesn't get a config
+                // or relaunch. This is required because normally nav-bar contributes
+                // to configuration bounds (via nondecorframe).
+                Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+                        .windowConfiguration.getAppBounds());
+                adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+                        - mSplitLayout.mSecondary.top);
+                wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+                wct.setScreenSizeDp(mSplits.mSecondary.token,
+                        mSplits.mSecondary.configuration.screenWidthDp,
+                        mSplits.mSecondary.configuration.screenHeightDp);
+            } else {
+                wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+                wct.setAppBounds(mSplits.mSecondary.token, null);
+                wct.setScreenSizeDp(mSplits.mSecondary.token,
+                        SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+            }
+            try {
+                ActivityTaskManager.getTaskOrganizerController()
+                        .applyContainerTransaction(wct, null /* organizer */);
+            } catch (RemoteException e) {
+            }
+
+            // Update all the adjusted-for-ime states
+            mView.setAdjustedForIme(mTargetShown, mTargetShown
+                    ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
+                    : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
+            setAdjustedForIme(mTargetShown);
+        }
+
+        @Override
+        public void onImePositionChanged(int displayId, int imeTop,
+                SurfaceControl.Transaction t) {
+            if (mAnimation != null) {
+                // Not synchronized with IME anymore, so return.
+                return;
+            }
+            final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
+            final float progress = mTargetShown ? fraction : 1.f - fraction;
+            onProgress(progress, t);
+        }
+
+        @Override
+        public void onImeEndPositioning(int displayId, boolean cancelled,
+                SurfaceControl.Transaction t) {
+            if (mAnimation != null) {
+                // Not synchronized with IME anymore, so return.
+                return;
+            }
+            onEnd(cancelled, t);
+        }
+
+        private void onProgress(float progress, SurfaceControl.Transaction t) {
+            if (mTargetAdjusted != mAdjusted) {
+                final float fraction = mTargetAdjusted ? progress : 1.f - progress;
+                mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
+                mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
+                mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+                        mSplitLayout.mAdjustedSecondary);
+            }
+            final float invProg = 1.f - progress;
+            final float targetPrimaryDim =
+                    (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+            final float targetSecondaryDim =
+                    (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+            mView.setResizeDimLayer(t, true /* primary */,
+                    mLastPrimaryDim * invProg + progress * targetPrimaryDim);
+            mView.setResizeDimLayer(t, false /* primary */,
+                    mLastSecondaryDim * invProg + progress * targetSecondaryDim);
+        }
+
+        private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
+            if (!cancelled) {
+                onProgress(1.f, t);
+                mAdjusted = mTargetAdjusted;
+                mImeWasShown = mTargetShown;
+                mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
+                mLastPrimaryDim =
+                        (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+                mLastSecondaryDim =
+                        (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+            }
+        }
+
+        private void startAsyncAnimation() {
+            if (mAnimation != null) {
+                mAnimation.cancel();
+            }
+            mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
+            mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
+            if (mTargetAdjusted != mAdjusted) {
+                final float fraction =
+                        ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
+                final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
+                mAnimation.setCurrentFraction(progress);
+            }
+
+            mAnimation.addUpdateListener(animation -> {
+                SurfaceControl.Transaction t = mTransactionPool.acquire();
+                float value = (float) animation.getAnimatedValue();
+                onProgress(value, t);
+                t.apply();
+                mTransactionPool.release(t);
+            });
+            mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
+            mAnimation.addListener(new AnimatorListenerAdapter() {
+                private boolean mCancel = false;
                 @Override
-                public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
-                        boolean imeShouldShow, SurfaceControl.Transaction t) {
-                    mSecondaryHasFocus = getSecondaryHasFocus(displayId);
-                    mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
-                            && !mSplitLayout.mDisplayLayout.isLandscape();
-                    mHiddenTop = hiddenTop;
-                    mShownTop = shownTop;
-                    mTargetShown = imeShouldShow;
-                    if (mLastAdjustTop < 0) {
-                        mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
-                    }
-                    if (mAnimation != null || (mImeWasShown && imeShouldShow
-                            && mTargetAdjusted != mAdjusted)) {
-                        // We need to animate adjustment independently of the IME position, so
-                        // start our own animation to drive adjustment. This happens when a
-                        // different split's editor has gained focus while the IME is still visible.
-                        startAsyncAnimation();
-                    }
-                    // Reposition the server's secondary split position so that it evaluates
-                    // insets properly.
-                    WindowContainerTransaction wct = new WindowContainerTransaction();
-                    if (mTargetAdjusted) {
-                        mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
-                        wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
-                        // "Freeze" the configuration size so that the app doesn't get a config
-                        // or relaunch. This is required because normally nav-bar contributes
-                        // to configuration bounds (via nondecorframe).
-                        Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
-                                .windowConfiguration.getAppBounds());
-                        adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
-                                - mSplitLayout.mSecondary.top);
-                        wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
-                        wct.setScreenSizeDp(mSplits.mSecondary.token,
-                                mSplits.mSecondary.configuration.screenWidthDp,
-                                mSplits.mSecondary.configuration.screenHeightDp);
-                    } else {
-                        wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
-                        wct.setAppBounds(mSplits.mSecondary.token, null);
-                        wct.setScreenSizeDp(mSplits.mSecondary.token,
-                                SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
-                    }
-                    try {
-                        ActivityTaskManager.getTaskOrganizerController()
-                                .applyContainerTransaction(wct, null /* organizer */);
-                    } catch (RemoteException e) {
-                    }
-
-                    // Update all the adjusted-for-ime states
-                    mView.setAdjustedForIme(mTargetShown, mTargetShown
-                            ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
-                            : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
-                    setAdjustedForIme(mTargetShown);
+                public void onAnimationCancel(Animator animation) {
+                    mCancel = true;
                 }
-
                 @Override
-                public void onImePositionChanged(int displayId, int imeTop,
-                        SurfaceControl.Transaction t) {
-                    if (mAnimation != null) {
-                        // Not synchronized with IME anymore, so return.
-                        return;
-                    }
-                    final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
-                    final float progress = mTargetShown ? fraction : 1.f - fraction;
-                    onProgress(progress, t);
+                public void onAnimationEnd(Animator animation) {
+                    SurfaceControl.Transaction t = mTransactionPool.acquire();
+                    onEnd(mCancel, t);
+                    t.apply();
+                    mTransactionPool.release(t);
+                    mAnimation = null;
                 }
-
-                @Override
-                public void onImeEndPositioning(int displayId, boolean cancelled,
-                        SurfaceControl.Transaction t) {
-                    if (mAnimation != null) {
-                        // Not synchronized with IME anymore, so return.
-                        return;
-                    }
-                    onEnd(cancelled, t);
-                }
-
-                private void onProgress(float progress, SurfaceControl.Transaction t) {
-                    if (mTargetAdjusted != mAdjusted) {
-                        final float fraction = mTargetAdjusted ? progress : 1.f - progress;
-                        mLastAdjustTop =
-                                (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
-                        mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
-                        mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
-                                mSplitLayout.mAdjustedSecondary);
-                    }
-                    final float invProg = 1.f - progress;
-                    final float targetPrimaryDim = (mSecondaryHasFocus && mTargetShown)
-                            ? ADJUSTED_NONFOCUS_DIM : 0.f;
-                    final float targetSecondaryDim = (!mSecondaryHasFocus && mTargetShown)
-                            ? ADJUSTED_NONFOCUS_DIM : 0.f;
-                    mView.setResizeDimLayer(t, true /* primary */,
-                            mLastPrimaryDim * invProg + progress * targetPrimaryDim);
-                    mView.setResizeDimLayer(t, false /* primary */,
-                            mLastSecondaryDim * invProg + progress * targetSecondaryDim);
-                }
-
-                private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
-                    if (!cancelled) {
-                        onProgress(1.f, t);
-                        mAdjusted = mTargetAdjusted;
-                        mImeWasShown = mTargetShown;
-                        mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
-                        mLastPrimaryDim =
-                                (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
-                        mLastSecondaryDim =
-                                (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
-                    }
-                }
-
-                private void startAsyncAnimation() {
-                    if (mAnimation != null) {
-                        mAnimation.cancel();
-                    }
-                    mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
-                    mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
-                    if (mTargetAdjusted != mAdjusted) {
-                        final float fraction =
-                                ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
-                        final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
-                        mAnimation.setCurrentFraction(progress);
-                    }
-
-                    mAnimation.addUpdateListener(animation -> {
-                        SurfaceControl.Transaction t = mTransactionPool.acquire();
-                        float value = (float) animation.getAnimatedValue();
-                        onProgress(value, t);
-                        t.apply();
-                        mTransactionPool.release(t);
-                    });
-                    mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
-                    mAnimation.addListener(new AnimatorListenerAdapter() {
-                        private boolean mCancel = false;
-                        @Override
-                        public void onAnimationCancel(Animator animation) {
-                            mCancel = true;
-                        }
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            SurfaceControl.Transaction t = mTransactionPool.acquire();
-                            onEnd(mCancel, t);
-                            t.apply();
-                            mTransactionPool.release(t);
-                            mAnimation = null;
-                        }
-                    });
-                    mAnimation.start();
-                }
-            };
+            });
+            mAnimation.start();
+        }
+    }
+    private final DividerImeController mImePositionProcessor = new DividerImeController();
 
     public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
             DisplayController displayController, SystemWindows systemWindows,
@@ -513,44 +509,39 @@
         }
     }
 
-    private void setHomeStackResizable(boolean resizable) {
-        if (mHomeStackResizable == resizable) {
-            return;
-        }
-        mHomeStackResizable = resizable;
-        if (!inSplitMode()) {
-            return;
-        }
-        WindowManagerProxy.applyHomeTasksMinimized(mSplitLayout, mSplits.mSecondary.token);
-    }
-
-    private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
-            final boolean isHomeStackResizable) {
-        setHomeStackResizable(isHomeStackResizable);
-        if (animDuration > 0) {
-            mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
-        } else {
-            mView.setMinimizedDockStack(minimized, isHomeStackResizable);
-        }
-        updateTouchable();
-    }
-
     /** Switch to minimized state if appropriate */
     public void setMinimized(final boolean minimized) {
         mHandler.post(() -> {
-            if (!inSplitMode()) {
-                return;
-            }
-            if (mMinimized == minimized) {
-                return;
-            }
-            mMinimized = minimized;
-            WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized);
-            mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
-            updateTouchable();
+            setHomeMinimized(minimized, mHomeStackResizable);
         });
     }
 
+    private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        // Update minimized state
+        if (mMinimized != minimized) {
+            mMinimized = minimized;
+        }
+        // Always set this because we could be entering split when mMinimized is already true
+        wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+        // Update home-stack resizability
+        if (mHomeStackResizable != homeStackResizable) {
+            mHomeStackResizable = homeStackResizable;
+            if (inSplitMode()) {
+                WindowManagerProxy.applyHomeTasksMinimized(
+                        mSplitLayout, mSplits.mSecondary.token, wct);
+            }
+        }
+
+        // Sync state to DividerView if it exists.
+        if (mView != null) {
+            mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
+        }
+        updateTouchable();
+        WindowManagerProxy.applyContainerTransaction(wct);
+    }
+
     void setAdjustedForIme(boolean adjustedForIme) {
         if (mAdjustedForIme == adjustedForIme) {
             return;
@@ -646,46 +637,24 @@
     }
 
     void ensureMinimizedSplit() {
-        final boolean wasMinimized = mMinimized;
-        mMinimized = true;
-        setHomeStackResizable(mSplits.mSecondary.isResizable());
-        WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */);
+        setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
         if (!inSplitMode()) {
             // Wasn't in split-mode yet, so enter now.
             if (DEBUG) {
                 Log.d(TAG, " entering split mode with minimized=true");
             }
             updateVisibility(true /* visible */);
-        } else if (!wasMinimized) {
-            if (DEBUG) {
-                Log.d(TAG, " in split mode, but minimizing ");
-            }
-            // Was already in split-mode, update just minimized state.
-            updateMinimizedDockedStack(mMinimized, getAnimDuration(),
-                    mHomeStackResizable);
         }
     }
 
     void ensureNormalSplit() {
-        if (mMinimized) {
-            WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */);
-        }
+        setHomeMinimized(false /* minimized */, mHomeStackResizable);
         if (!inSplitMode()) {
             // Wasn't in split-mode, so enter now.
             if (DEBUG) {
                 Log.d(TAG, " enter split mode unminimized ");
             }
-            mMinimized = false;
             updateVisibility(true /* visible */);
         }
-        if (mMinimized) {
-            // Was in minimized state, so leave that.
-            if (DEBUG) {
-                Log.d(TAG, " in split mode already, but unminimizing ");
-            }
-            mMinimized = false;
-            updateMinimizedDockedStack(mMinimized, getAnimDuration(),
-                    mHomeStackResizable);
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 3020a25..729df38 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -88,6 +88,9 @@
     }
 
     public void setTouchable(boolean touchable) {
+        if (mView == null) {
+            return;
+        }
         boolean changed = false;
         if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
             mLp.flags |= FLAG_NOT_TOUCHABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 5cc8799..48ea4ae 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -88,7 +88,7 @@
     }
 
     @Override
-    public void taskVanished(IWindowContainer container) {
+    public void taskVanished(RunningTaskInfo taskInfo) {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 167c33a..fea57a3 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -21,6 +21,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.graphics.Rect;
@@ -137,17 +138,13 @@
         return resizable;
     }
 
-    static void applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent) {
-        applyHomeTasksMinimized(layout, parent, null /* transaction */);
-    }
-
     /**
      * Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
      * split is minimized. This actually "sticks out" of the secondary split area, but when in
      * minimized mode, the secondary split gets a 'negative' crop to expose it.
      */
     static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
-            WindowContainerTransaction t) {
+            @NonNull WindowContainerTransaction wct) {
         // Resize the home/recents stacks to the larger minimized-state size
         final Rect homeBounds;
         final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
@@ -158,19 +155,9 @@
             homeBounds = new Rect(0, 0, layout.mDisplayLayout.width(),
                     layout.mDisplayLayout.height());
         }
-        WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction();
         for (int i = homeStacks.size() - 1; i >= 0; --i) {
             wct.setBounds(homeStacks.get(i), homeBounds);
         }
-        if (t != null) {
-            return isHomeResizable;
-        }
-        try {
-            ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
-                    null /* organizer */);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to resize home stacks ", e);
-        }
         return isHomeResizable;
     }
 
@@ -301,10 +288,8 @@
         }
     }
 
-    static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) {
+    static void applyContainerTransaction(WindowContainerTransaction wct) {
         try {
-            WindowContainerTransaction wct = new WindowContainerTransaction();
-            wct.setFocusable(splits.mPrimary.token, focusable);
             ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
                     null /* organizer */);
         } catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
index 53605e5..7c06157 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
@@ -282,7 +282,7 @@
                     .withCornerRadius(mCornerRadius)
                     .withVisibility(true)
                     .build();
-            mSyncRtTransactionApplier.scheduleApply(params);
+            mSyncRtTransactionApplier.scheduleApply(true /* earlyWakeup */, params);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 88888d1..269a7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.systemui.statusbar.notification.interruption
+package com.android.systemui.statusbar.notification
 
 import android.content.Context
 import android.media.MediaMetadata
@@ -24,7 +24,6 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index b572502..df21f0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.interruption;
+package com.android.systemui.statusbar.notification;
 
 import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -27,9 +27,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -42,7 +39,7 @@
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final VisualStabilityManager mVisualStabilityManager;
     private final StatusBarStateController mStatusBarStateController;
-    private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private final NotificationListener mNotificationListener;
 
     private HeadsUpManager mHeadsUpManager;
@@ -55,13 +52,13 @@
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
             StatusBarStateController statusBarStateController,
-            NotificationInterruptStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationListener notificationListener,
             HeadsUpManager headsUpManager) {
         mRemoteInputManager = remoteInputManager;
         mVisualStabilityManager = visualStabilityManager;
         mStatusBarStateController = statusBarStateController;
-        mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mNotificationListener = notificationListener;
         mHeadsUpManager = headsUpManager;
 
@@ -97,7 +94,7 @@
         if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) {
             // Possible for shouldHeadsUp to change between the inflation starting and ending.
             // If it does and we no longer need to heads up, we should free the view.
-            if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
+            if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
                 mHeadsUpManager.showNotification(entry);
                 if (!mStatusBarStateController.isDozing()) {
                     // Mark as seen immediately
@@ -112,7 +109,7 @@
     private void updateAlertState(NotificationEntry entry) {
         boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification());
         // includes check for whether this notification should be filtered:
-        boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry);
+        boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
         final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey());
         if (wasAlerting) {
             if (shouldAlert) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 46d5044..bbf2dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -14,35 +14,33 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.notification.interruption;
+package com.android.systemui.statusbar.notification;
 
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
 import android.app.NotificationManager;
-import android.content.ContentResolver;
+import android.content.Context;
 import android.database.ContentObserver;
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
 import android.os.PowerManager;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.Dependency;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
@@ -50,84 +48,120 @@
  * Provides heads-up and pulsing state for notification entries.
  */
 @Singleton
-public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
+public class NotificationInterruptionStateProvider {
+
     private static final String TAG = "InterruptionStateProvider";
-    private static final boolean DEBUG = true; //false;
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_HEADS_UP = true;
     private static final boolean ENABLE_HEADS_UP = true;
     private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
-    private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>();
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationFilter mNotificationFilter;
-    private final ContentResolver mContentResolver;
+    private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+
+    private final Context mContext;
     private final PowerManager mPowerManager;
     private final IDreamManager mDreamManager;
-    private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     private final BatteryController mBatteryController;
-    private final ContentObserver mHeadsUpObserver;
-    private HeadsUpManager mHeadsUpManager;
 
+    private NotificationPresenter mPresenter;
+    private HeadsUpManager mHeadsUpManager;
+    private HeadsUpSuppressor mHeadsUpSuppressor;
+
+    private ContentObserver mHeadsUpObserver;
     @VisibleForTesting
     protected boolean mUseHeadsUp = false;
+    private boolean mDisableNotificationAlerts;
 
     @Inject
-    public NotificationInterruptStateProviderImpl(
-            ContentResolver contentResolver,
+    public NotificationInterruptionStateProvider(Context context, NotificationFilter filter,
+            StatusBarStateController stateController, BatteryController batteryController) {
+        this(context,
+                (PowerManager) context.getSystemService(Context.POWER_SERVICE),
+                IDreamManager.Stub.asInterface(
+                        ServiceManager.checkService(DreamService.DREAM_SERVICE)),
+                new AmbientDisplayConfiguration(context),
+                filter,
+                batteryController,
+                stateController);
+    }
+
+    @VisibleForTesting
+    protected NotificationInterruptionStateProvider(
+            Context context,
             PowerManager powerManager,
             IDreamManager dreamManager,
             AmbientDisplayConfiguration ambientDisplayConfiguration,
             NotificationFilter notificationFilter,
             BatteryController batteryController,
-            StatusBarStateController statusBarStateController,
-            HeadsUpManager headsUpManager,
-            @Main Handler mainHandler) {
-        mContentResolver = contentResolver;
+            StatusBarStateController statusBarStateController) {
+        mContext = context;
         mPowerManager = powerManager;
         mDreamManager = dreamManager;
         mBatteryController = batteryController;
         mAmbientDisplayConfiguration = ambientDisplayConfiguration;
         mNotificationFilter = notificationFilter;
         mStatusBarStateController = statusBarStateController;
-        mHeadsUpManager = headsUpManager;
-        mHeadsUpObserver = new ContentObserver(mainHandler) {
-            @Override
-            public void onChange(boolean selfChange) {
-                boolean wasUsing = mUseHeadsUp;
-                mUseHeadsUp = ENABLE_HEADS_UP
-                        && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
-                        mContentResolver,
-                        Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
-                        Settings.Global.HEADS_UP_OFF);
-                Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
-                if (wasUsing != mUseHeadsUp) {
-                    if (!mUseHeadsUp) {
-                        Log.d(TAG, "dismissing any existing heads up notification on "
-                                + "disable event");
-                        mHeadsUpManager.releaseAllImmediately();
+    }
+
+    /** Sets up late-binding dependencies for this component. */
+    public void setUpWithPresenter(
+            NotificationPresenter notificationPresenter,
+            HeadsUpManager headsUpManager,
+            HeadsUpSuppressor headsUpSuppressor) {
+        setUpWithPresenter(notificationPresenter, headsUpManager, headsUpSuppressor,
+                new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        boolean wasUsing = mUseHeadsUp;
+                        mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
+                                && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
+                                mContext.getContentResolver(),
+                                Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+                                Settings.Global.HEADS_UP_OFF);
+                        Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+                        if (wasUsing != mUseHeadsUp) {
+                            if (!mUseHeadsUp) {
+                                Log.d(TAG,
+                                        "dismissing any existing heads up notification on disable"
+                                                + " event");
+                                mHeadsUpManager.releaseAllImmediately();
+                            }
+                        }
                     }
-                }
-            }
-        };
+                });
+    }
+
+    /** Sets up late-binding dependencies for this component. */
+    public void setUpWithPresenter(
+            NotificationPresenter notificationPresenter,
+            HeadsUpManager headsUpManager,
+            HeadsUpSuppressor headsUpSuppressor,
+            ContentObserver observer) {
+        mPresenter = notificationPresenter;
+        mHeadsUpManager = headsUpManager;
+        mHeadsUpSuppressor = headsUpSuppressor;
+        mHeadsUpObserver = observer;
 
         if (ENABLE_HEADS_UP) {
-            mContentResolver.registerContentObserver(
+            mContext.getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
                     true,
                     mHeadsUpObserver);
-            mContentResolver.registerContentObserver(
+            mContext.getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                     mHeadsUpObserver);
         }
         mHeadsUpObserver.onChange(true); // set up
     }
 
-    @Override
-    public void addSuppressor(NotificationInterruptSuppressor suppressor) {
-        mSuppressors.add(suppressor);
-    }
-
-    @Override
+    /**
+     * Whether the notification should appear as a bubble with a fly-out on top of the screen.
+     *
+     * @param entry the entry to check
+     * @return true if the entry should bubble up, false otherwise
+     */
     public boolean shouldBubbleUp(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
 
@@ -167,8 +201,12 @@
         return true;
     }
 
-
-    @Override
+    /**
+     * Whether the notification should peek in from the top and alert the user.
+     *
+     * @param entry the entry to check
+     * @return true if the entry should heads up, false otherwise
+     */
     public boolean shouldHeadsUp(NotificationEntry entry) {
         if (mStatusBarStateController.isDozing()) {
             return shouldHeadsUpWhenDozing(entry);
@@ -177,17 +215,6 @@
         }
     }
 
-    /**
-     * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
-     * incoming calls.
-     */
-    @Override
-    public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
-        return entry.getSbn().getNotification().fullScreenIntent != null
-                && (!shouldHeadsUp(entry)
-                || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
-    }
-
     private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
         StatusBarNotification sbn = entry.getSbn();
 
@@ -244,15 +271,13 @@
             return false;
         }
 
-        for (int i = 0; i < mSuppressors.size(); i++) {
-            if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
-                if (DEBUG_HEADS_UP) {
-                    Log.d(TAG, "No heads up: aborted by suppressor: "
-                            + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
-                }
-                return false;
+        if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
+            if (DEBUG_HEADS_UP) {
+                Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
             }
+            return false;
         }
+
         return true;
     }
 
@@ -300,7 +325,7 @@
             }
             return false;
         }
-        return true;
+         return true;
     }
 
     /**
@@ -309,7 +334,8 @@
      * @param entry the entry to check
      * @return true if these checks pass, false if the notification should not alert
      */
-    private boolean canAlertCommon(NotificationEntry entry) {
+    @VisibleForTesting
+    public boolean canAlertCommon(NotificationEntry entry) {
         StatusBarNotification sbn = entry.getSbn();
 
         if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -326,16 +352,6 @@
             }
             return false;
         }
-
-        for (int i = 0; i < mSuppressors.size(); i++) {
-            if (mSuppressors.get(i).suppressInterruptions(entry)) {
-                if (DEBUG_HEADS_UP) {
-                    Log.d(TAG, "No alerting: aborted by suppressor: "
-                            + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
-                }
-                return false;
-            }
-        }
         return true;
     }
 
@@ -345,17 +361,15 @@
      * @param entry the entry to check
      * @return true if these checks pass, false if the notification should not alert
      */
-    private boolean canAlertAwakeCommon(NotificationEntry entry) {
+    @VisibleForTesting
+    public boolean canAlertAwakeCommon(NotificationEntry entry) {
         StatusBarNotification sbn = entry.getSbn();
 
-        for (int i = 0; i < mSuppressors.size(); i++) {
-            if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) {
-                if (DEBUG_HEADS_UP) {
-                    Log.d(TAG, "No alerting: aborted by suppressor: "
-                            + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
-                }
-                return false;
+        if (mPresenter.isDeviceInVrMode()) {
+            if (DEBUG_HEADS_UP) {
+                Log.d(TAG, "No alerting: no huns or vr mode");
             }
+            return false;
         }
 
         if (isSnoozedPackage(sbn)) {
@@ -378,4 +392,54 @@
     private boolean isSnoozedPackage(StatusBarNotification sbn) {
         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
     }
+
+    /** Sets whether to disable all alerts. */
+    public void setDisableNotificationAlerts(boolean disableNotificationAlerts) {
+        mDisableNotificationAlerts = disableNotificationAlerts;
+        mHeadsUpObserver.onChange(true);
+    }
+
+    /** Whether all alerts are disabled. */
+    @VisibleForTesting
+    public boolean areNotificationAlertsDisabled() {
+        return mDisableNotificationAlerts;
+    }
+
+    /** Whether HUNs should be used. */
+    @VisibleForTesting
+    public boolean getUseHeadsUp() {
+        return mUseHeadsUp;
+    }
+
+    protected NotificationPresenter getPresenter() {
+        return mPresenter;
+    }
+
+    /**
+     * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
+     * incoming calls.
+     *
+     * @param entry the entry that was added
+     * @return {@code true} if we should launch the full screen intent
+     */
+    public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+        return entry.getSbn().getNotification().fullScreenIntent != null
+            && (!shouldHeadsUp(entry)
+                || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+    }
+
+    /** A component which can suppress heads-up notifications due to the overall state of the UI. */
+    public interface HeadsUpSuppressor {
+        /**
+         * Returns false if the provided notification is ineligible for heads-up according to this
+         * component.
+         *
+         * @param entry entry of the notification that might be heads upped
+         * @param sbn   notification that might be heads upped
+         * @return false if the notification can not be heads upped
+         */
+        boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
+
+    }
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 2747696..8a23e37 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification
 
 import android.animation.ObjectAnimator
+import android.content.Context
 import android.util.FloatProperty
 import com.android.systemui.Interpolators
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -25,10 +26,10 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator
 import com.android.systemui.statusbar.phone.DozeParameters
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.NotificationIconAreaController
 import com.android.systemui.statusbar.phone.PanelExpansionListener
-import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
 
 import javax.inject.Inject
@@ -36,14 +37,15 @@
 
 @Singleton
 class NotificationWakeUpCoordinator @Inject constructor(
-    private val mHeadsUpManager: HeadsUpManager,
-    private val statusBarStateController: StatusBarStateController,
-    private val bypassController: KeyguardBypassController,
-    private val dozeParameters: DozeParameters
-) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener {
+        private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
+        private val statusBarStateController: StatusBarStateController,
+        private val bypassController: KeyguardBypassController,
+        private val dozeParameters: DozeParameters)
+    : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
+        PanelExpansionListener {
 
-    private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>(
-        "notificationVisibility") {
+    private val mNotificationVisibility
+            = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
 
         override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
             coordinator.setVisibilityAmount(value)
@@ -76,10 +78,10 @@
             field = value
             willWakeUp = false
             if (value) {
-                if (mNotificationsVisible && !mNotificationsVisibleForExpansion &&
-                    !bypassController.bypassEnabled) {
+                if (mNotificationsVisible && !mNotificationsVisibleForExpansion
+                        && !bypassController.bypassEnabled) {
                     // We're waking up while pulsing, let's make sure the animation looks nice
-                    mStackScroller.wakeUpFromPulse()
+                    mStackScroller.wakeUpFromPulse();
                 }
                 if (bypassController.bypassEnabled && !mNotificationsVisible) {
                     // Let's make sure our huns become visible once we are waking up in case
@@ -98,7 +100,7 @@
         }
 
     private var collapsedEnoughToHide: Boolean = false
-    lateinit var iconAreaController: NotificationIconAreaController
+    lateinit var iconAreaController : NotificationIconAreaController
 
     var pulsing: Boolean = false
         set(value) {
@@ -130,8 +132,8 @@
             var canShow = pulsing
             if (bypassController.bypassEnabled) {
                 // We also allow pulsing on the lock screen!
-                canShow = canShow || (wakingUp || willWakeUp || fullyAwake) &&
-                    statusBarStateController.state == StatusBarState.KEYGUARD
+                canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
+                        && statusBarStateController.state == StatusBarState.KEYGUARD
                 // We want to hide the notifications when collapsed too much
                 if (collapsedEnoughToHide) {
                     canShow = false
@@ -141,7 +143,7 @@
         }
 
     init {
-        mHeadsUpManager.addListener(this)
+        mHeadsUpManagerPhone.addListener(this)
         statusBarStateController.addCallback(this)
         addListener(object : WakeUpListener {
             override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
@@ -153,7 +155,7 @@
                             increaseSpeed = false)
                 }
             }
-        })
+        });
     }
 
     fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -176,55 +178,46 @@
      * @param animate should this change be animated
      * @param increaseSpeed should the speed be increased of the animation
      */
-    fun setNotificationsVisibleForExpansion(
-        visible: Boolean,
-        animate: Boolean,
-        increaseSpeed: Boolean
-    ) {
+    fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean,
+                                                    increaseSpeed: Boolean) {
         mNotificationsVisibleForExpansion = visible
         updateNotificationVisibility(animate, increaseSpeed)
         if (!visible && mNotificationsVisible) {
             // If we stopped expanding and we're still visible because we had a pulse that hasn't
             // times out, let's release them all to make sure were not stuck in a state where
             // notifications are visible
-            mHeadsUpManager.releaseAllImmediately()
+            mHeadsUpManagerPhone.releaseAllImmediately()
         }
     }
 
     fun addListener(listener: WakeUpListener) {
-        wakeUpListeners.add(listener)
+        wakeUpListeners.add(listener);
     }
 
     fun removeListener(listener: WakeUpListener) {
-        wakeUpListeners.remove(listener)
+        wakeUpListeners.remove(listener);
     }
 
-    private fun updateNotificationVisibility(
-        animate: Boolean,
-        increaseSpeed: Boolean
-    ) {
+    private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
         // TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
-        var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications()
+        var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
         visible = visible && canShowPulsingHuns
 
         if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
             // let's not make notifications invisible while waking up, otherwise the animation
             // is strange
-            return
+            return;
         }
         setNotificationsVisible(visible, animate, increaseSpeed)
     }
 
-    private fun setNotificationsVisible(
-        visible: Boolean,
-        animate: Boolean,
-        increaseSpeed: Boolean
-    ) {
+    private fun setNotificationsVisible(visible: Boolean, animate: Boolean,
+                                        increaseSpeed: Boolean) {
         if (mNotificationsVisible == visible) {
             return
         }
         mNotificationsVisible = visible
-        mVisibilityAnimator?.cancel()
+        mVisibilityAnimator?.cancel();
         if (animate) {
             notifyAnimationStart(visible)
             startVisibilityAnimation(increaseSpeed)
@@ -237,8 +230,8 @@
         if (updateDozeAmountIfBypass()) {
             return
         }
-        if (linear != 1.0f && linear != 0.0f &&
-            (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
+        if (linear != 1.0f && linear != 0.0f
+                && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
             // Let's notify the scroller that an animation started
             notifyAnimationStart(mLinearDozeAmount == 1.0f)
         }
@@ -252,17 +245,17 @@
         mStackScroller.setDozeAmount(mDozeAmount)
         updateHideAmount()
         if (changed && linear == 0.0f) {
-            setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
+            setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
             setNotificationsVisibleForExpansion(visible = false, animate = false,
                     increaseSpeed = false)
         }
     }
 
     override fun onStateChanged(newState: Int) {
-        updateDozeAmountIfBypass()
+        updateDozeAmountIfBypass();
         if (bypassController.bypassEnabled &&
-                newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
-            (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
+                newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED
+                && (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
             // We're leaving shade locked. Let's animate the notifications away
             setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
             setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
@@ -273,23 +266,23 @@
     override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
         val collapsedEnough = expansion <= 0.9f
         if (collapsedEnough != this.collapsedEnoughToHide) {
-            val couldShowPulsingHuns = canShowPulsingHuns
+            val couldShowPulsingHuns = canShowPulsingHuns;
             this.collapsedEnoughToHide = collapsedEnough
             if (couldShowPulsingHuns && !canShowPulsingHuns) {
                 updateNotificationVisibility(animate = true, increaseSpeed = true)
-                mHeadsUpManager.releaseAllImmediately()
+                mHeadsUpManagerPhone.releaseAllImmediately()
             }
         }
     }
 
     private fun updateDozeAmountIfBypass(): Boolean {
         if (bypassController.bypassEnabled) {
-            var amount = 1.0f
-            if (statusBarStateController.state == StatusBarState.SHADE ||
-                statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
-                amount = 0.0f
+            var amount = 1.0f;
+            if (statusBarStateController.state == StatusBarState.SHADE
+                    || statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+                amount = 0.0f;
             }
-            setDozeAmount(amount, amount)
+            setDozeAmount(amount,  amount)
             return true
         }
         return false
@@ -307,7 +300,7 @@
         visibilityAnimator.setInterpolator(Interpolators.LINEAR)
         var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
         if (increaseSpeed) {
-            duration = (duration.toFloat() / 1.5F).toLong()
+            duration = (duration.toFloat() / 1.5F).toLong();
         }
         visibilityAnimator.setDuration(duration)
         visibilityAnimator.start()
@@ -318,7 +311,7 @@
         mLinearVisibilityAmount = visibilityAmount
         mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
                 visibilityAmount)
-        handleAnimationFinished()
+        handleAnimationFinished();
         updateHideAmount()
     }
 
@@ -329,7 +322,7 @@
         }
     }
 
-    fun getWakeUpHeight(): Float {
+    fun getWakeUpHeight() : Float {
         return mStackScroller.wakeUpHeight
     }
 
@@ -337,7 +330,7 @@
         val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
         val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
         mStackScroller.setHideAmount(linearAmount, amount)
-        notificationsFullyHidden = linearAmount == 1.0f
+        notificationsFullyHidden = linearAmount == 1.0f;
     }
 
     private fun notifyAnimationStart(awake: Boolean) {
@@ -368,7 +361,7 @@
                     // if we animate, we see the shelf briefly visible. Instead we fully animate
                     // the notification and its background out
                     animate = false
-                } else if (!wakingUp && !willWakeUp) {
+                } else if (!wakingUp && !willWakeUp){
                     // TODO: look that this is done properly and not by anyone else
                     entry.setHeadsUpAnimatingAway(true)
                     mEntrySetToClearWhenFinished.add(entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 4beeede..e8a62e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -37,8 +37,8 @@
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NotificationClicker;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
 import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -66,7 +66,7 @@
 
     private static final String TAG = "NotificationViewManager";
 
-    private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
 
     private final Context mContext;
     private final NotifBindPipeline mNotifBindPipeline;
@@ -97,7 +97,7 @@
             StatusBarStateController statusBarStateController,
             NotificationGroupManager notificationGroupManager,
             NotificationGutsManager notificationGutsManager,
-            NotificationInterruptStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             Provider<RowInflaterTask> rowInflaterTaskProvider,
             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
         mContext = context;
@@ -106,7 +106,7 @@
         mMessagingUtil = notificationMessagingUtil;
         mNotificationRemoteInputManager = notificationRemoteInputManager;
         mNotificationLockscreenUserManager = notificationLockscreenUserManager;
-        mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mRowInflaterTaskProvider = rowInflaterTaskProvider;
         mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
     }
@@ -243,7 +243,7 @@
         params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
         params.setUseLowPriority(entry.isAmbient());
 
-        if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
+        if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
             params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
         }
         //TODO: Replace this API with RowContentBindParams directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index cd6affd..e425ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,8 +31,10 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
@@ -42,10 +44,9 @@
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
 import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
-import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -57,7 +58,6 @@
 
 import javax.inject.Singleton;
 
-import dagger.Binds;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
@@ -127,7 +127,7 @@
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
             StatusBarStateController statusBarStateController,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationListener notificationListener,
             HeadsUpManager headsUpManager) {
         return new NotificationAlertingManager(
@@ -135,7 +135,7 @@
                 remoteInputManager,
                 visualStabilityManager,
                 statusBarStateController,
-                notificationInterruptStateProvider,
+                notificationInterruptionStateProvider,
                 notificationListener,
                 headsUpManager);
     }
@@ -148,13 +148,22 @@
             @UiBackground Executor uiBgExecutor,
             NotificationEntryManager entryManager,
             StatusBarStateController statusBarStateController,
-            NotificationLogger.ExpansionStateLogger expansionStateLogger) {
+            NotificationLogger.ExpansionStateLogger expansionStateLogger,
+            NotificationPanelLogger notificationPanelLogger) {
         return new NotificationLogger(
                 notificationListener,
                 uiBgExecutor,
                 entryManager,
                 statusBarStateController,
-                expansionStateLogger);
+                expansionStateLogger,
+                notificationPanelLogger);
+    }
+
+    /** Provides an instance of {@link NotificationPanelLogger} */
+    @Singleton
+    @Provides
+    static NotificationPanelLogger provideNotificationPanelLogger() {
+        return new NotificationPanelLoggerImpl();
     }
 
     /** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
@@ -201,9 +210,4 @@
             NotificationEntryManager entryManager) {
         return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
     }
-
-    /** */
-    @Binds
-    NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
-            NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
deleted file mode 100644
index 3292a8f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ /dev/null
@@ -1,59 +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.systemui.statusbar.notification.interruption;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/**
- * Provides bubble-up and heads-up state for notification entries.
- *
- * When a notification is heads-up when dozing, this is also called "pulsing."
- */
-public interface NotificationInterruptStateProvider {
-    /**
-     * If the device is awake (not dozing):
-     *  Whether the notification should peek in from the top and alert the user.
-     *
-     * If the device is dozing:
-     *  Whether the notification should show the ambient view of the notification ("pulse").
-     *
-     * @param entry the entry to check
-     * @return true if the entry should heads up, false otherwise
-     */
-    boolean shouldHeadsUp(NotificationEntry entry);
-
-    /**
-     * Whether the notification should appear as a bubble with a fly-out on top of the screen.
-     *
-     * @param entry the entry to check
-     * @return true if the entry should bubble up, false otherwise
-     */
-    boolean shouldBubbleUp(NotificationEntry entry);
-
-    /**
-     * Whether to launch the entry's full screen intent when the entry is added.
-     *
-     * @param entry the entry that was added
-     * @return {@code true} if we should launch the full screen intent
-     */
-    boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
-
-    /**
-     * Add a component that can suppress visual interruptions.
-     */
-    void addSuppressor(NotificationInterruptSuppressor suppressor);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
deleted file mode 100644
index c19f8bd..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
+++ /dev/null
@@ -1,64 +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.systemui.statusbar.notification.interruption;
-
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-/** A component which can suppress visual interruptions of notifications such as heads-up and
- *  bubble-up.
- */
-public interface NotificationInterruptSuppressor {
-    /**
-     * A unique name to identify this suppressor.
-     */
-    default String getName() {
-        return this.getClass().getName();
-    }
-
-    /**
-     * Returns true if the provided notification is, when the device is awake, ineligible for
-     * heads-up according to this component.
-     *
-     * @param entry entry of the notification that might heads-up
-     * @return true if the heads up interruption should be suppressed when the device is awake
-     */
-    default boolean suppressAwakeHeadsUp(NotificationEntry entry) {
-        return false;
-    }
-
-    /**
-     * Returns true if the provided notification is, when the device is awake, ineligible for
-     * heads-up or bubble-up according to this component.
-     *
-     * @param entry entry of the notification that might heads-up or bubble-up
-     * @return true if interruptions should be suppressed when the device is awake
-     */
-    default boolean suppressAwakeInterruptions(NotificationEntry entry) {
-        return false;
-    }
-
-    /**
-     * Returns true if the provided notification is, regardless of awake/dozing state,
-     * ineligible for heads-up or bubble-up according to this component.
-     *
-     * @param entry entry of the notification that might heads-up or bubble-up
-     * @return true if interruptions should be suppressed
-     */
-    default boolean suppressInterruptions(NotificationEntry entry) {
-        return false;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 6e161c9..ad04788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -70,6 +70,7 @@
     private final NotificationListenerService mNotificationListener;
     private final Executor mUiBgExecutor;
     private final NotificationEntryManager mEntryManager;
+    private final NotificationPanelLogger mNotificationPanelLogger;
     private HeadsUpManager mHeadsUpManager;
     private final ExpansionStateLogger mExpansionStateLogger;
 
@@ -198,13 +199,15 @@
             @UiBackground Executor uiBgExecutor,
             NotificationEntryManager entryManager,
             StatusBarStateController statusBarStateController,
-            ExpansionStateLogger expansionStateLogger) {
+            ExpansionStateLogger expansionStateLogger,
+            NotificationPanelLogger notificationPanelLogger) {
         mNotificationListener = notificationListener;
         mUiBgExecutor = uiBgExecutor;
         mEntryManager = entryManager;
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mExpansionStateLogger = expansionStateLogger;
+        mNotificationPanelLogger = notificationPanelLogger;
         // Not expected to be destroyed, don't need to unsubscribe
         statusBarStateController.addCallback(this);
 
@@ -264,6 +267,8 @@
         // (Note that in cases where the scroller does emit events, this
         // additional event doesn't break anything.)
         mNotificationLocationsChangedListener.onChildLocationsChanged();
+        mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
+                mEntryManager.getVisibleNotifications());
     }
 
     private void setDozing(boolean dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
new file mode 100644
index 0000000..9a25c48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -0,0 +1,95 @@
+/*
+ * 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.logging;
+
+import android.annotation.Nullable;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.List;
+/**
+ * Statsd logging for notification panel.
+ */
+public interface NotificationPanelLogger {
+
+    /**
+     * Log a NOTIFICATION_PANEL_REPORTED statsd event.
+     * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+     */
+    void logPanelShown(boolean isLockscreen,
+            @Nullable List<NotificationEntry> visibleNotifications);
+
+    enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+        @UiEvent(doc = "Notification panel shown from status bar.")
+        NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
+        @UiEvent(doc = "Notification panel shown from lockscreen.")
+        NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201);
+
+        private final int mId;
+        NotificationPanelEvent(int id) {
+            mId = id;
+        }
+        @Override public int getId() {
+            return mId;
+        }
+
+        public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) {
+            return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN :
+                    NOTIFICATION_PANEL_OPEN_STATUS_BAR;
+        }
+    }
+
+    /**
+     * Composes a NotificationsList proto from the list of visible notifications.
+     * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+     * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
+     */
+    static Notifications.NotificationList toNotificationProto(
+            @Nullable List<NotificationEntry> visibleNotifications) {
+        Notifications.NotificationList notificationList = new Notifications.NotificationList();
+        if (visibleNotifications == null) {
+            return notificationList;
+        }
+        final Notifications.Notification[] proto_array =
+                new Notifications.Notification[visibleNotifications.size()];
+        int i = 0;
+        for (NotificationEntry ne : visibleNotifications) {
+            final StatusBarNotification n = ne.getSbn();
+            if (n != null) {
+                final Notifications.Notification proto = new Notifications.Notification();
+                proto.uid = n.getUid();
+                proto.packageName = n.getPackageName();
+                if (n.getInstanceId() != null) {
+                    proto.instanceId = n.getInstanceId().getId();
+                }
+                // TODO set np.groupInstanceId
+                if (n.getNotification() != null) {
+                    proto.isGroupSummary = n.getNotification().isGroupSummary();
+                }
+                proto.section = 1 + ne.getBucket();  // We want 0 to mean not set / unknown
+                proto_array[i] = proto;
+            }
+            ++i;
+        }
+        notificationList.notifications = proto_array;
+        return notificationList;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
new file mode 100644
index 0000000..75a6019
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.logging;
+
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.List;
+
+/**
+ * Normal implementation of NotificationPanelLogger.
+ */
+public class NotificationPanelLoggerImpl implements NotificationPanelLogger {
+    @Override
+    public void logPanelShown(boolean isLockscreen,
+            List<NotificationEntry> visibleNotifications) {
+        final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto(
+                visibleNotifications);
+        SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+                /* int event_id */ NotificationPanelEvent.fromLockscreen(isLockscreen).getId(),
+                /* int num_notifications*/ proto.notifications.length,
+                /* byte[] notifications*/ MessageNano.toByteArray(proto));
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
new file mode 100644
index 0000000..552a5fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -0,0 +1,49 @@
+/*
+ * 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.logging;
+
+/**
+ * NotificationList proto from atoms.proto, duplicated here so that it's accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message Notification {
+    // The notifying app's uid and package.
+    optional int32 uid = 1;
+    optional string package_name = 2;
+    // A small system-assigned identifier for the notification.
+    optional int32 instance_id = 3;
+
+    // Grouping information.
+    optional int32 group_instance_id = 4;
+    optional bool is_group_summary = 5;
+
+    // The section of the shade that the notification is in.
+    // See NotificationSectionsManager.PriorityBucket.
+    enum NotificationSection {
+        SECTION_UNKNOWN = 0;
+        SECTION_HEADS_UP = 1;
+        SECTION_PEOPLE = 2;
+        SECTION_ALERTING = 3;
+        SECTION_SILENT = 4;
+    }
+    optional NotificationSection section = 6;
+}
+
+message NotificationList {
+    repeated Notification notifications = 1;  // An ordered sequence of notifications.
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 287ede4..b3a62d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -185,14 +185,15 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -403,9 +404,10 @@
 
     private final NotificationGutsManager mGutsManager;
     private final NotificationLogger mNotificationLogger;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private final NotificationViewHierarchyManager mViewHierarchyManager;
     private final KeyguardViewMediator mKeyguardViewMediator;
-    protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    private final NotificationAlertingManager mNotificationAlertingManager;
 
     // for disabling the status bar
     private int mDisabled1 = 0;
@@ -619,9 +621,10 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
+            NotificationAlertingManager notificationAlertingManager,
             DisplayMetrics displayMetrics,
             MetricsLogger metricsLogger,
             @UiBackground Executor uiBgExecutor,
@@ -698,9 +701,10 @@
         mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
         mGutsManager = notificationGutsManager;
         mNotificationLogger = notificationLogger;
-        mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mViewHierarchyManager = notificationViewHierarchyManager;
         mKeyguardViewMediator = keyguardViewMediator;
+        mNotificationAlertingManager = notificationAlertingManager;
         mDisplayMetrics = displayMetrics;
         mMetricsLogger = metricsLogger;
         mUiBgExecutor = uiBgExecutor;
@@ -1234,9 +1238,9 @@
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
                 mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController,
                 mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
-                mKeyguardStateController, mKeyguardIndicationController,
-                this /* statusBar */, mShadeController, mCommandQueue, mInitController,
-                mNotificationInterruptStateProvider);
+                mNotificationAlertingManager, mKeyguardStateController,
+                mKeyguardIndicationController,
+                this /* statusBar */, mShadeController, mCommandQueue, mInitController);
 
         mNotificationShelf.setOnActivatedListener(mPresenter);
         mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
@@ -1585,9 +1589,8 @@
         }
 
         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
-            if (areNotificationAlertsDisabled()) {
-                mHeadsUpManager.releaseAllImmediately();
-            }
+            mNotificationInterruptionStateProvider.setDisableNotificationAlerts(
+                    (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
         }
 
         if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
@@ -1602,10 +1605,6 @@
         }
     }
 
-    boolean areNotificationAlertsDisabled() {
-        return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
-    }
-
     protected H createHandler() {
         return new StatusBar.H();
     }
@@ -2333,7 +2332,7 @@
 
     void checkBarModes() {
         if (mDemoMode) return;
-        if (mNotificationShadeWindowViewController != null) {
+        if (mNotificationShadeWindowViewController != null && getStatusBarTransitions() != null) {
             checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
         }
         mNavigationBarController.checkNavBarModes(mDisplayId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 53fa263..e1a20b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -68,12 +68,12 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -108,7 +108,7 @@
     private final NotifCollection mNotifCollection;
     private final FeatureFlags mFeatureFlags;
     private final StatusBarStateController mStatusBarStateController;
-    private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     private final MetricsLogger mMetricsLogger;
     private final Context mContext;
     private final NotificationPanelViewController mNotificationPanel;
@@ -142,7 +142,7 @@
             NotificationLockscreenUserManager lockscreenUserManager,
             ShadeController shadeController, StatusBar statusBar,
             KeyguardStateController keyguardStateController,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
             Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor,
             ActivityIntentHelper activityIntentHelper, BubbleController bubbleController,
@@ -167,7 +167,7 @@
         mActivityStarter = activityStarter;
         mEntryManager = entryManager;
         mStatusBarStateController = statusBarStateController;
-        mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
         mMetricsLogger = metricsLogger;
         mAssistManagerLazy = assistManagerLazy;
         mGroupManager = groupManager;
@@ -436,7 +436,7 @@
     }
 
     private void handleFullScreenIntent(NotificationEntry entry) {
-        if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
+        if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
             if (shouldSuppressFullScreenIntent(entry)) {
                 if (DEBUG) {
                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.getKey());
@@ -603,7 +603,7 @@
         private final ActivityIntentHelper mActivityIntentHelper;
         private final BubbleController mBubbleController;
         private NotificationPanelViewController mNotificationPanelViewController;
-        private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
+        private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
         private final ShadeController mShadeController;
         private NotificationPresenter mNotificationPresenter;
         private ActivityLaunchAnimator mActivityLaunchAnimator;
@@ -626,7 +626,7 @@
                 NotificationGroupManager groupManager,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 KeyguardStateController keyguardStateController,
-                NotificationInterruptStateProvider notificationInterruptStateProvider,
+                NotificationInterruptionStateProvider notificationInterruptionStateProvider,
                 MetricsLogger metricsLogger,
                 LockPatternUtils lockPatternUtils,
                 @Main Handler mainThreadHandler,
@@ -654,7 +654,7 @@
             mGroupManager = groupManager;
             mLockscreenUserManager = lockscreenUserManager;
             mKeyguardStateController = keyguardStateController;
-            mNotificationInterruptStateProvider = notificationInterruptStateProvider;
+            mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
             mMetricsLogger = metricsLogger;
             mLockPatternUtils = lockPatternUtils;
             mMainThreadHandler = mainThreadHandler;
@@ -712,7 +712,7 @@
                     mShadeController,
                     mStatusBar,
                     mKeyguardStateController,
-                    mNotificationInterruptStateProvider,
+                    mNotificationInterruptionStateProvider,
                     mMetricsLogger,
                     mLockPatternUtils,
                     mMainThreadHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 79cea91..30d6b507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,13 +60,13 @@
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -98,6 +98,8 @@
             (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
     private final NotificationEntryManager mEntryManager =
             Dependency.get(NotificationEntryManager.class);
+    private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
+            Dependency.get(NotificationInterruptionStateProvider.class);
     private final NotificationMediaManager mMediaManager =
             Dependency.get(NotificationMediaManager.class);
     private final VisualStabilityManager mVisualStabilityManager =
@@ -138,13 +140,13 @@
             ScrimController scrimController,
             ActivityLaunchAnimator activityLaunchAnimator,
             DynamicPrivacyController dynamicPrivacyController,
+            NotificationAlertingManager notificationAlertingManager,
             KeyguardStateController keyguardStateController,
             KeyguardIndicationController keyguardIndicationController,
             StatusBar statusBar,
             ShadeController shadeController,
             CommandQueue commandQueue,
-            InitController initController,
-            NotificationInterruptStateProvider notificationInterruptStateProvider) {
+            InitController initController) {
         mContext = context;
         mKeyguardStateController = keyguardStateController;
         mNotificationPanel = panel;
@@ -214,7 +216,8 @@
             mEntryManager.addNotificationLifetimeExtender(mGutsManager);
             mEntryManager.addNotificationLifetimeExtenders(
                     remoteInputManager.getLifetimeExtenders());
-            notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
+            mNotificationInterruptionStateProvider.setUpWithPresenter(
+                    this, mHeadsUpManager, this::canHeadsUp);
             mLockscreenUserManager.setUpWithPresenter(this);
             mMediaManager.setUpWithPresenter(this);
             mVisualStabilityManager.setUpWithPresenter(this);
@@ -333,6 +336,39 @@
         return mEntryManager.hasActiveNotifications();
     }
 
+    public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
+        if (mStatusBar.isOccluded()) {
+            boolean devicePublic = mLockscreenUserManager.
+                    isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+            boolean userPublic = devicePublic
+                    || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+            boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+            if (userPublic && needsRedaction) {
+                // TODO(b/135046837): we can probably relax this with dynamic privacy
+                return false;
+            }
+        }
+
+        if (!mCommandQueue.panelsEnabled()) {
+            if (DEBUG) {
+                Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+            }
+            return false;
+        }
+
+        if (sbn.getNotification().fullScreenIntent != null) {
+            if (mAccessibilityManager.isTouchExplorationEnabled()) {
+                if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+                return false;
+            } else {
+                // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
+                return !mKeyguardStateController.isShowing()
+                        || mStatusBar.isOccluded();
+            }
+        }
+        return true;
+    }
+
     @Override
     public void onUserSwitched(int newUserId) {
         // Begin old BaseStatusBar.userSwitched
@@ -471,66 +507,4 @@
             }
         }
     };
-
-    private final NotificationInterruptSuppressor mInterruptSuppressor =
-            new NotificationInterruptSuppressor() {
-        @Override
-        public String getName() {
-            return TAG;
-        }
-
-        @Override
-        public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
-            final StatusBarNotification sbn = entry.getSbn();
-            if (mStatusBar.isOccluded()) {
-                boolean devicePublic = mLockscreenUserManager
-                        .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
-                boolean userPublic = devicePublic
-                        || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
-                boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
-                if (userPublic && needsRedaction) {
-                    // TODO(b/135046837): we can probably relax this with dynamic privacy
-                    return true;
-                }
-            }
-
-            if (!mCommandQueue.panelsEnabled()) {
-                if (DEBUG) {
-                    Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
-                }
-                return true;
-            }
-
-            if (sbn.getNotification().fullScreenIntent != null) {
-                // we don't allow head-up on the lockscreen (unless there's a
-                // "showWhenLocked" activity currently showing)  if
-                // the potential HUN has a fullscreen intent
-                if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) {
-                    if (DEBUG) {
-                        Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
-                                + sbn.getKey());
-                    }
-                    return true;
-                }
-
-                if (mAccessibilityManager.isTouchExplorationEnabled()) {
-                    if (DEBUG) {
-                        Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
-                    }
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
-        public boolean suppressAwakeInterruptions(NotificationEntry entry) {
-            return isDeviceInVrMode();
-        }
-
-        @Override
-        public boolean suppressInterruptions(NotificationEntry entry) {
-            return mStatusBar.areNotificationAlertsDisabled();
-        }
-    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index 824e0f0..eec8d50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -56,12 +56,13 @@
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -138,9 +139,10 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptStateProvider notificationInterruptStateProvider,
+            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
+            NotificationAlertingManager notificationAlertingManager,
             DisplayMetrics displayMetrics,
             MetricsLogger metricsLogger,
             @UiBackground Executor uiBgExecutor,
@@ -216,9 +218,10 @@
                 remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
                 notificationLogger,
-                notificationInterruptStateProvider,
+                notificationInterruptionStateProvider,
                 notificationViewHierarchyManager,
                 keyguardViewMediator,
+                notificationAlertingManager,
                 displayMetrics,
                 metricsLogger,
                 uiBgExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index cf9d8e1..24b9685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,12 @@
     boolean isAodPowerSave();
 
     /**
+     * Set reverse state.
+     * @param isReverse true if turn on reverse, false otherwise
+     */
+    default void setReverseState(boolean isReverse) {}
+
+    /**
      * A listener that will be notified whenever a change in battery level or power save mode has
      * occurred.
      */
@@ -63,6 +69,9 @@
 
         default void onPowerSaveChanged(boolean isPowerSave) {
         }
+
+        default void onReverseChanged(boolean isReverse, int level, String name) {
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d3e6f53..35954d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -59,13 +59,13 @@
 
     private final EnhancedEstimates mEstimates;
     private final BroadcastDispatcher mBroadcastDispatcher;
-    private final ArrayList<BatteryController.BatteryStateChangeCallback>
+    protected final ArrayList<BatteryController.BatteryStateChangeCallback>
             mChangeCallbacks = new ArrayList<>();
     private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
     private final Handler mMainHandler;
     private final Handler mBgHandler;
-    private final Context mContext;
+    protected final Context mContext;
 
     private int mLevel;
     private boolean mPluggedIn;
@@ -80,7 +80,7 @@
 
     @VisibleForTesting
     @Inject
-    BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+    protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
             PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
             @Main Handler mainHandler, @Background Handler bgHandler) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 30db37c..f31f8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -43,6 +43,7 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
@@ -101,7 +102,7 @@
                 new ContentObserver(mBgHandler) {
 
                     @Override
-                    public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+                    public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
                             int userId) {
                         if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
                         if (ActivityManager.getCurrentUser() == userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index b2a5f5b..2452218 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -262,7 +262,8 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+        public void onChange(boolean selfChange, java.util.Collection<Uri> uris,
+                int flags, int userId) {
             if (userId == ActivityManager.getCurrentUser()) {
                 for (Uri u : uris) {
                     reloadSetting(u);
diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
index 2276ba1..812a1e4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt
@@ -358,7 +358,7 @@
             targetObjectIsStuckTo = targetObjectIsInMagneticFieldOf
             cancelAnimations()
             magnetListener.onStuckToTarget(targetObjectIsInMagneticFieldOf!!)
-            animateStuckToTarget(targetObjectIsInMagneticFieldOf!!, velX, velY, false)
+            animateStuckToTarget(targetObjectIsInMagneticFieldOf, velX, velY, false)
 
             vibrateIfEnabled(VibrationEffect.EFFECT_HEAVY_CLICK)
         } else if (targetObjectIsInMagneticFieldOf == null && objectStuckToTarget) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 6199181..353fe62 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -50,6 +50,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Arrays;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 // Need to run tests on main looper because LiveData operations such as setData, observe,
@@ -126,7 +128,7 @@
         when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
         when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+        mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
         // THEN the result is null, indicated the default clock face should be used.
         assertThat(mClockManager.getCurrentClock()).isNull();
     }
@@ -136,7 +138,7 @@
         // GIVEN that settings is set to the bubble clock face
         when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+        mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
         // THEN the plugin is the bubble clock face.
         assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
     }
@@ -146,7 +148,7 @@
         // GIVEN that settings is set to the bubble clock face
         when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+        mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
         // THEN the plugin is the bubble clock face.
         ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
         verify(mMockListener1).onClockChanged(captor.capture());
@@ -158,7 +160,7 @@
         // GIVEN that settings is set to the bubble clock face
         when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
         // WHEN settings change event is fired
-        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+        mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
         // THEN the listeners receive separate instances of the Bubble clock plugin.
         ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
         ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
@@ -175,7 +177,7 @@
         // custom clock face.
         when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
         // WHEN settings change event is fired
-        mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+        mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
         // THEN the result is null.
         assertThat(mClockManager.getCurrentClock()).isNull();
     }
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 977d0bb..78160c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -45,11 +45,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.res.Resources;
-import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.face.FaceManager;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
 import android.service.notification.ZenModeConfig;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -65,12 +61,14 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -229,17 +227,15 @@
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
-        TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
-                new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
-                        mock(PowerManager.class),
-                        mock(IDreamManager.class),
-                        mock(AmbientDisplayConfiguration.class),
+        TestableNotificationInterruptionStateProvider interruptionStateProvider =
+                new TestableNotificationInterruptionStateProvider(mContext,
                         mock(NotificationFilter.class),
                         mock(StatusBarStateController.class),
-                        mock(BatteryController.class),
-                        mock(HeadsUpManager.class),
-                        mock(Handler.class)
-                );
+                        mock(BatteryController.class));
+        interruptionStateProvider.setUpWithPresenter(
+                mock(NotificationPresenter.class),
+                mock(HeadsUpManager.class),
+                mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
         mBubbleData = new BubbleData(mContext);
         when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
         mBubbleController = new TestableBubbleController(
@@ -403,7 +399,8 @@
         // Switch which bubble is expanded
         mBubbleController.selectBubble(mRow.getEntry().getKey());
         mBubbleData.setExpanded(true);
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
 
@@ -496,21 +493,25 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow2.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry()));
 
         // Dismiss currently expanded
-        mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+        mBubbleController.removeBubble(
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
                 BubbleController.DISMISS_USER_GESTURE);
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
 
         // Make sure first bubble is selected
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
         // Dismiss that one
-        mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+        mBubbleController.removeBubble(
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
                 BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
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 7fc83da..5ef4cd2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -41,11 +41,7 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.content.res.Resources;
-import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.face.FaceManager;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
 import android.service.notification.ZenModeConfig;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -61,10 +57,12 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -132,19 +130,15 @@
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private FloatingContentCoordinator mFloatingContentCoordinator;
-
     @Captor
     private ArgumentCaptor<NotifCollectionListener> mNotifListenerCaptor;
-
     private TestableBubbleController mBubbleController;
     private NotificationShadeWindowController mNotificationShadeWindowController;
     private NotifCollectionListener mEntryListener;
-
     private NotificationTestHelper mNotificationTestHelper;
     private ExpandableNotificationRow mRow;
     private ExpandableNotificationRow mRow2;
     private ExpandableNotificationRow mNonBubbleNotifRow;
-
     @Mock
     private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
     @Mock
@@ -218,17 +212,15 @@
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
-        TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
-                new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
-                        mock(PowerManager.class),
-                        mock(IDreamManager.class),
-                        mock(AmbientDisplayConfiguration.class),
+        TestableNotificationInterruptionStateProvider interruptionStateProvider =
+                new TestableNotificationInterruptionStateProvider(mContext,
                         mock(NotificationFilter.class),
                         mock(StatusBarStateController.class),
-                        mock(BatteryController.class),
-                        mock(HeadsUpManager.class),
-                        mock(Handler.class)
-                );
+                        mock(BatteryController.class));
+        interruptionStateProvider.setUpWithPresenter(
+                mock(NotificationPresenter.class),
+                mock(HeadsUpManager.class),
+                mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
         mBubbleData = new BubbleData(mContext);
         when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
         mBubbleController = new TestableBubbleController(
@@ -313,7 +305,7 @@
         verify(mNotifCallback, times(1)).invalidateNotifications(anyString());
         assertNotNull(mBubbleData.getBubbleWithKey(mRow.getEntry().getKey()));
         mBubbleController.updateBubble(mRow2.getEntry());
-        verify(mNotifCallback,  times(2)).invalidateNotifications(anyString());
+        verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
         assertNotNull(mBubbleData.getBubbleWithKey(mRow2.getEntry().getKey()));
         assertTrue(mBubbleController.hasBubbles());
 
@@ -383,7 +375,8 @@
         // Switch which bubble is expanded
         mBubbleController.selectBubble(mRow.getEntry().getKey());
         mBubbleData.setExpanded(true);
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow.getEntry()));
 
@@ -475,21 +468,25 @@
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().getKey());
 
         // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow2.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
                 mRow2.getEntry()));
 
         // Dismiss currently expanded
-        mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+        mBubbleController.removeBubble(
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
                 BubbleController.DISMISS_USER_GESTURE);
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey());
 
         // Make sure first bubble is selected
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubble().getEntry());
+        assertEquals(mRow.getEntry(),
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().getKey());
 
         // Dismiss that one
-        mBubbleController.removeBubble(stackView.getExpandedBubble().getEntry(),
+        mBubbleController.removeBubble(
+                mBubbleData.getBubbleWithKey(stackView.getExpandedBubble().getKey()).getEntry(),
                 BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
@@ -649,7 +646,7 @@
     }
 
     @Test
-    public void removeBubble_intercepted()  {
+    public void removeBubble_intercepted() {
         mEntryListener.onEntryAdded(mRow.getEntry());
         mBubbleController.updateBubble(mRow.getEntry());
 
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..de1fb41 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -23,8 +23,8 @@
 import com.android.systemui.statusbar.FeatureFlags;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +44,7 @@
             ShadeController shadeController,
             BubbleData data,
             ConfigurationController configurationController,
-            NotificationInterruptStateProvider interruptionStateProvider,
+            NotificationInterruptionStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager lockscreenUserManager,
             NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
deleted file mode 100644
index 17dc76b..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
+++ /dev/null
@@ -1,55 +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.systemui.bubbles;
-
-import android.content.ContentResolver;
-import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.service.dreams.IDreamManager;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-public class TestableNotificationInterruptStateProviderImpl
-        extends NotificationInterruptStateProviderImpl {
-
-    TestableNotificationInterruptStateProviderImpl(
-            ContentResolver contentResolver,
-            PowerManager powerManager,
-            IDreamManager dreamManager,
-            AmbientDisplayConfiguration ambientDisplayConfiguration,
-            NotificationFilter filter,
-            StatusBarStateController statusBarStateController,
-            BatteryController batteryController,
-            HeadsUpManager headsUpManager,
-            Handler mainHandler) {
-        super(contentResolver,
-                powerManager,
-                dreamManager,
-                ambientDisplayConfiguration,
-                filter,
-                batteryController,
-                statusBarStateController,
-                headsUpManager,
-                mainHandler);
-        mUseHeadsUp = true;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
new file mode 100644
index 0000000..5d192b2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
@@ -0,0 +1,35 @@
+/*
+ * 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.bubbles;
+
+import android.content.Context;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+public class TestableNotificationInterruptionStateProvider
+        extends NotificationInterruptionStateProvider {
+
+    TestableNotificationInterruptionStateProvider(Context context,
+            NotificationFilter filter, StatusBarStateController controller,
+            BatteryController batteryController) {
+        super(context, filter, controller, batteryController);
+        mUseHeadsUp = 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 183dde8..c70c56a 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
@@ -234,7 +234,7 @@
             loaded = true
             assertEquals(1, controls.size)
             val controlStatus = controls[0]
-            assertEquals(ControlStatus(control, false), controlStatus)
+            assertEquals(ControlStatus(control, TEST_COMPONENT, false), controlStatus)
 
             assertTrue(favorites.isEmpty())
             assertFalse(data.errorOnLoad)
@@ -265,10 +265,10 @@
             loaded = true
             assertEquals(2, controls.size)
             val controlStatus = controls.first { it.control.controlId == TEST_CONTROL_ID }
-            assertEquals(ControlStatus(control, true), controlStatus)
+            assertEquals(ControlStatus(control, TEST_COMPONENT, true), controlStatus)
 
             val controlStatus2 = controls.first { it.control.controlId == TEST_CONTROL_ID_2 }
-            assertEquals(ControlStatus(control2, false), controlStatus2)
+            assertEquals(ControlStatus(control2, TEST_COMPONENT, false), controlStatus2)
 
             assertEquals(1, favorites.size)
             assertEquals(TEST_CONTROL_ID, favorites[0])
@@ -340,6 +340,8 @@
 
         controlLoadCallbackCaptor.value.error("")
 
+        delayableExecutor.runAllReady()
+
         assertTrue(loaded)
     }
 
@@ -519,7 +521,7 @@
     }
 
     @Test
-    fun testReplaceFavoritesForStructure_noFavorites() {
+    fun testReplaceFavoritesForStructure_noExistingFavorites() {
         controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
         delayableExecutor.runAllReady()
 
@@ -529,6 +531,16 @@
     }
 
     @Test
+    fun testReplaceFavoritesForStructure_doNotStoreEmptyStructure() {
+        controller.replaceFavoritesForStructure(
+            StructureInfo(TEST_COMPONENT, "Home", emptyList<ControlInfo>()))
+        delayableExecutor.runAllReady()
+
+        assertEquals(0, controller.countFavoritesForComponent(TEST_COMPONENT))
+        assertEquals(emptyList<ControlInfo>(), controller.getFavoritesForComponent(TEST_COMPONENT))
+    }
+
+    @Test
     fun testReplaceFavoritesForStructure_differentComponentsAreFilteredOut() {
         controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
         controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO_2)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
index 68e1ec1..133df2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.controls.management
 
 import android.app.PendingIntent
+import android.content.ComponentName
 import android.service.controls.Control
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
@@ -78,6 +79,7 @@
                     Control.StatelessBuilder("$idPrefix$it", pendingIntent)
                             .setZone(zoneMap(it))
                             .build(),
+                    ComponentName("", ""),
                     it in favoritesIndices
             )
         }
@@ -189,4 +191,4 @@
             assertTrue(sameControl(it.first, it.second))
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 85e937e..13a7708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -30,7 +30,6 @@
 import com.android.systemui.util.time.FakeSystemClock
 import org.junit.After
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -38,6 +37,7 @@
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.`when`
+import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
@@ -98,74 +98,18 @@
     }
 
     @Test
+    fun testInitialStateListening() {
+        verify(mockSL).setListening(true)
+        verify(mockSL).reload()
+    }
+
+    @Test
     fun testStartsOnUser() {
         assertEquals(user, controller.currentUserId)
     }
 
     @Test
-    fun testNoServices_notListening() {
-        assertTrue(controller.getCurrentServices().isEmpty())
-    }
-
-    @Test
-    fun testStartListening_onFirstCallback() {
-        controller.addCallback(mockCallback)
-        executor.runAllReady()
-
-        verify(mockSL).setListening(true)
-    }
-
-    @Test
-    fun testStartListening_onlyOnce() {
-        controller.addCallback(mockCallback)
-        controller.addCallback(mockCallbackOther)
-
-        executor.runAllReady()
-
-        verify(mockSL).setListening(true)
-    }
-
-    @Test
-    fun testStopListening_callbackRemoved() {
-        controller.addCallback(mockCallback)
-
-        executor.runAllReady()
-
-        controller.removeCallback(mockCallback)
-
-        executor.runAllReady()
-
-        verify(mockSL).setListening(false)
-    }
-
-    @Test
-    fun testStopListening_notWhileRemainingCallbacks() {
-        controller.addCallback(mockCallback)
-        controller.addCallback(mockCallbackOther)
-
-        executor.runAllReady()
-
-        controller.removeCallback(mockCallback)
-
-        executor.runAllReady()
-
-        verify(mockSL, never()).setListening(false)
-    }
-
-    @Test
-    fun testReloadOnFirstCallbackAdded() {
-        controller.addCallback(mockCallback)
-        executor.runAllReady()
-
-        verify(mockSL).reload()
-    }
-
-    @Test
     fun testCallbackCalledWhenAdded() {
-        `when`(mockSL.reload()).then {
-            serviceListingCallbackCaptor.value.onServicesReloaded(emptyList())
-        }
-
         controller.addCallback(mockCallback)
         executor.runAllReady()
         verify(mockCallback).onServicesUpdated(any())
@@ -209,5 +153,11 @@
         controller.changeUser(UserHandle.of(otherUser))
         executor.runAllReady()
         assertEquals(otherUser, controller.currentUserId)
+
+        val inOrder = inOrder(mockSL)
+        inOrder.verify(mockSL).setListening(false)
+        inOrder.verify(mockSL).addCallback(any()) // We add a callback because we replaced the SL
+        inOrder.verify(mockSL).setListening(true)
+        inOrder.verify(mockSL).reload()
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
index 9ffc29e..c330b38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.controls.management
 
 import android.app.PendingIntent
+import android.content.ComponentName
 import android.service.controls.Control
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
@@ -70,6 +71,7 @@
                     Control.StatelessBuilder("$idPrefix$it", pendingIntent)
                             .setZone((it % 3).toString())
                             .build(),
+                    ComponentName("", ""),
                     it in favoritesIndices
             )
         }
@@ -195,4 +197,4 @@
 
         verifyNoMoreInteractions(allAdapter, favoritesAdapter)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
similarity index 63%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
index f9c62e1..1693e7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.statusbar.notification.interruption;
+package com.android.systemui.statusbar;
 
 
 import static android.app.Notification.FLAG_BUBBLE;
@@ -30,14 +30,15 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.service.dreams.IDreamManager;
@@ -49,6 +50,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -66,7 +68,7 @@
  */
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
-public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
+public class NotificationInterruptionStateProviderTest extends SysuiTestCase {
 
     @Mock
     PowerManager mPowerManager;
@@ -79,36 +81,38 @@
     @Mock
     StatusBarStateController mStatusBarStateController;
     @Mock
+    NotificationPresenter mPresenter;
+    @Mock
     HeadsUpManager mHeadsUpManager;
     @Mock
-    BatteryController mBatteryController;
+    NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
     @Mock
-    Handler mMockHandler;
+    BatteryController mBatteryController;
 
-    private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
+    private NotificationInterruptionStateProvider mNotifInterruptionStateProvider;
 
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
         mNotifInterruptionStateProvider =
-                new NotificationInterruptStateProviderImpl(
-                        mContext.getContentResolver(),
+                new TestableNotificationInterruptionStateProvider(mContext,
                         mPowerManager,
                         mDreamManager,
                         mAmbientDisplayConfiguration,
                         mNotificationFilter,
-                        mBatteryController,
                         mStatusBarStateController,
-                        mHeadsUpManager,
-                        mMockHandler);
+                        mBatteryController);
 
-        mNotifInterruptionStateProvider.mUseHeadsUp = true;
+        mNotifInterruptionStateProvider.setUpWithPresenter(
+                mPresenter,
+                mHeadsUpManager,
+                mHeadsUpSuppressor);
     }
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will
+     * {@link NotificationInterruptionStateProvider#canAlertCommon(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills group suppression check.
      */
     private void ensureStateForAlertCommon() {
@@ -117,16 +121,17 @@
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#canAlertAwakeCommon(NotificationEntry)} will
+     * {@link NotificationInterruptionStateProvider#canAlertAwakeCommon(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills launch fullscreen check.
      */
     private void ensureStateForAlertAwakeCommon() {
+        when(mPresenter.isDeviceInVrMode()).thenReturn(false);
         when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
     }
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
+     * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills importance & DND checks.
      */
     private void ensureStateForHeadsUpWhenAwake() throws RemoteException {
@@ -136,11 +141,12 @@
         when(mStatusBarStateController.isDozing()).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
         when(mPowerManager.isScreenOn()).thenReturn(true);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
     }
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
+     * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills importance & DND checks.
      */
     private void ensureStateForHeadsUpWhenDozing() {
@@ -152,7 +158,7 @@
 
     /**
      * Sets up the state such that any requests to
-     * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will
+     * {@link NotificationInterruptionStateProvider#shouldBubbleUp(NotificationEntry)} will
      * pass as long its provided NotificationEntry fulfills importance & bubble checks.
      */
     private void ensureStateForBubbleUp() {
@@ -160,53 +166,75 @@
         ensureStateForAlertAwakeCommon();
     }
 
+    /**
+     * Ensure that the disabled state is set correctly.
+     */
     @Test
-    public void testDefaultSuppressorDoesNotSuppress() {
-        // GIVEN a suppressor without any overrides
-        final NotificationInterruptSuppressor defaultSuppressor =
-                new NotificationInterruptSuppressor() {
-                    @Override
-                    public String getName() {
-                        return "defaultSuppressor";
-                    }
-                };
+    public void testDisableNotificationAlerts() {
+        // Enabled by default
+        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
+
+        // Disable alerts
+        mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue();
+
+        // Enable alerts
+        mNotifInterruptionStateProvider.setDisableNotificationAlerts(false);
+        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
+    }
+
+    /**
+     * Ensure that the disabled alert state effects whether HUNs are enabled.
+     */
+    @Test
+    public void testHunSettingsChange_enabled_butAlertsDisabled() {
+        // Set up but without a mock change observer
+        mNotifInterruptionStateProvider.setUpWithPresenter(
+                mPresenter,
+                mHeadsUpManager,
+                mHeadsUpSuppressor);
+
+        // HUNs enabled by default
+        assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isTrue();
+
+        // Set alerts disabled
+        mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+
+        // No more HUNs
+        assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
+    }
+
+    /**
+     * Alerts can happen.
+     */
+    @Test
+    public void testCanAlertCommon_true() {
+        ensureStateForAlertCommon();
 
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-
-        // THEN this suppressor doesn't suppress anything by default
-        assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse();
-        assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse();
-        assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse();
+        assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue();
     }
 
+    /**
+     * Filtered out notifications don't alert.
+     */
     @Test
-    public void testShouldHeadsUpAwake() throws RemoteException {
-        ensureStateForHeadsUpWhenAwake();
+    public void testCanAlertCommon_false_filteredOut() {
+        ensureStateForAlertCommon();
+        when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
 
-        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+        assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
     }
 
+    /**
+     * Grouped notifications have different alerting behaviours, sometimes the alert for a
+     * grouped notification may be suppressed {@link android.app.Notification#GROUP_ALERT_CHILDREN}.
+     */
     @Test
-    public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
-        // GIVEN state for "heads up when awake" is true
-        ensureStateForHeadsUpWhenAwake();
+    public void testCanAlertCommon_false_suppressedForGroups() {
+        ensureStateForAlertCommon();
 
-        // WHEN this entry should be filtered out
-        NotificationEntry entry  = createNotification(IMPORTANCE_DEFAULT);
-        when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
-
-        // THEN we shouldn't heads up this entry
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
-    }
-
-    @Test
-    public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
-        // GIVEN state for "heads up when awake" is true
-        ensureStateForHeadsUpWhenAwake();
-
-        // WHEN the alert for a grouped notification is suppressed
-        // see {@link android.app.Notification#GROUP_ALERT_CHILDREN}
         NotificationEntry entry = new NotificationEntryBuilder()
                 .setPkg("a")
                 .setOpPkg("a")
@@ -219,40 +247,40 @@
                 .setImportance(IMPORTANCE_DEFAULT)
                 .build();
 
-        // THEN this entry shouldn't HUN
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+        assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
     }
 
+    /**
+     * HUNs while dozing can happen.
+     */
     @Test
-    public void testShouldHeadsUpWhenDozing() {
+    public void testShouldHeadsUpWhenDozing_true() {
         ensureStateForHeadsUpWhenDozing();
 
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
     }
 
+    /**
+     * Ambient display can show HUNs for new notifications, this may be disabled.
+     */
     @Test
-    public void testShouldNotHeadsUpWhenDozing_pulseDisabled() {
-        // GIVEN state for "heads up when dozing" is true
+    public void testShouldHeadsUpWhenDozing_false_pulseDisabled() {
         ensureStateForHeadsUpWhenDozing();
-
-        // WHEN pulsing (HUNs when dozing) is disabled
         when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(false);
 
-        // THEN this entry shouldn't HUN
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
+    /**
+     * If the device is not in ambient display or sleeping then we don't HUN.
+     */
     @Test
-    public void testShouldNotHeadsUpWhenDozing_notDozing() {
-        // GIVEN state for "heads up when dozing" is true
+    public void testShouldHeadsUpWhenDozing_false_notDozing() {
         ensureStateForHeadsUpWhenDozing();
-
-        // WHEN we're not dozing (in ambient display or sleeping)
         when(mStatusBarStateController.isDozing()).thenReturn(false);
 
-        // THEN this entry shouldn't HUN
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
@@ -262,7 +290,7 @@
      * {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}.
      */
     @Test
-    public void testShouldNotHeadsUpWhenDozing_suppressingAmbient() {
+    public void testShouldHeadsUpWhenDozing_false_suppressingAmbient() {
         ensureStateForHeadsUpWhenDozing();
 
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -273,18 +301,23 @@
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
+    /**
+     * Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
+     * get to pulse.
+     */
     @Test
-    public void testShouldNotHeadsUpWhenDozing_lessImportant() {
+    public void testShouldHeadsUpWhenDozing_false_lessImportant() {
         ensureStateForHeadsUpWhenDozing();
 
-        // Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
-        // get to pulse
         NotificationEntry entry = createNotification(IMPORTANCE_LOW);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
+    /**
+     * Heads up can happen.
+     */
     @Test
-    public void testShouldHeadsUp() throws RemoteException {
+    public void testShouldHeadsUp_true() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
 
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -292,11 +325,38 @@
     }
 
     /**
+     * Heads up notifications can be disabled in general.
+     */
+    @Test
+    public void testShouldHeadsUp_false_noHunsAllowed() throws RemoteException {
+        ensureStateForHeadsUpWhenAwake();
+
+        // Set alerts disabled, this should cause heads up to be false
+        mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
+        assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+    }
+
+    /**
+     * If the device is dozing, we don't show as heads up.
+     */
+    @Test
+    public void testShouldHeadsUp_false_dozing() throws RemoteException {
+        ensureStateForHeadsUpWhenAwake();
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+    }
+
+    /**
      * If the notification is a bubble, and the user is not on AOD / lockscreen, then
      * the bubble is shown rather than the heads up.
      */
     @Test
-    public void testShouldNotHeadsUp_bubble() throws RemoteException {
+    public void testShouldHeadsUp_false_bubble() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
 
         // Bubble bit only applies to interruption when we're in the shade
@@ -309,7 +369,7 @@
      * If we're not allowed to alert in general, we shouldn't be shown as heads up.
      */
     @Test
-    public void testShouldNotHeadsUp_filtered() throws RemoteException {
+    public void testShouldHeadsUp_false_alertCommonFalse() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
         // Make canAlertCommon false by saying it's filtered out
         when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
@@ -323,7 +383,7 @@
      * {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}.
      */
     @Test
-    public void testShouldNotHeadsUp_suppressPeek() throws RemoteException {
+    public void testShouldHeadsUp_false_suppressPeek() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
 
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -339,7 +399,7 @@
      * to show as a heads up.
      */
     @Test
-    public void testShouldNotHeadsUp_lessImportant() throws RemoteException {
+    public void testShouldHeadsUp_false_lessImportant() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
 
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -350,7 +410,7 @@
      * If the device is not in use then we shouldn't be shown as heads up.
      */
     @Test
-    public void testShouldNotHeadsUp_deviceNotInUse() throws RemoteException {
+    public void testShouldHeadsUp_false_deviceNotInUse() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
 
@@ -364,58 +424,61 @@
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
+    /**
+     * If something wants to suppress this heads up, then it shouldn't be shown as a heads up.
+     */
     @Test
-    public void testShouldNotHeadsUp_headsUpSuppressed() throws RemoteException {
+    public void testShouldHeadsUp_false_suppressed() throws RemoteException {
         ensureStateForHeadsUpWhenAwake();
-
-        // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
-        mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeHeadsUp);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(false);
 
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+        verify(mHeadsUpSuppressor).canHeadsUp(any(), any());
     }
 
+    /**
+     * On screen alerts don't happen when the device is in VR Mode.
+     */
     @Test
-    public void testShouldNotHeadsUpAwake_awakeInterruptsSuppressed() throws RemoteException {
-        ensureStateForHeadsUpWhenAwake();
+    public void testCanAlertAwakeCommon__false_vrMode() {
+        ensureStateForAlertAwakeCommon();
+        when(mPresenter.isDeviceInVrMode()).thenReturn(true);
 
-        // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
-        mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeInterruptions);
-
-        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+        assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
     }
 
     /**
      * On screen alerts don't happen when the notification is snoozed.
      */
     @Test
-    public void testShouldNotHeadsUp_snoozedPackage() {
-        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+    public void testCanAlertAwakeCommon_false_snoozedPackage() {
         ensureStateForAlertAwakeCommon();
+        when(mHeadsUpManager.isSnoozed(any())).thenReturn(true);
 
-        when(mHeadsUpManager.isSnoozed(entry.getSbn().getPackageName())).thenReturn(true);
-
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+        assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
     }
 
-
+    /**
+     * On screen alerts don't happen when that package has just launched fullscreen.
+     */
     @Test
-    public void testShouldNotHeadsUp_justLaunchedFullscreen() {
+    public void testCanAlertAwakeCommon_false_justLaunchedFullscreen() {
         ensureStateForAlertAwakeCommon();
 
-        // On screen alerts don't happen when that package has just launched fullscreen.
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
         entry.notifyFullScreenIntentLaunched();
 
-        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+        assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
     }
 
     /**
      * Bubbles can happen.
      */
     @Test
-    public void testShouldBubbleUp() {
+    public void testShouldBubbleUp_true() {
         ensureStateForBubbleUp();
         assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue();
     }
@@ -424,7 +487,7 @@
      * If the notification doesn't have permission to bubble, it shouldn't bubble.
      */
     @Test
-    public void shouldNotBubbleUp_notAllowedToBubble() {
+    public void shouldBubbleUp_false_notAllowedToBubble() {
         ensureStateForBubbleUp();
 
         NotificationEntry entry = createBubble();
@@ -439,7 +502,7 @@
      * If the notification isn't a bubble, it should definitely not show as a bubble.
      */
     @Test
-    public void shouldNotBubbleUp_notABubble() {
+    public void shouldBubbleUp_false_notABubble() {
         ensureStateForBubbleUp();
 
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -454,7 +517,7 @@
      * If the notification doesn't have bubble metadata, it shouldn't bubble.
      */
     @Test
-    public void shouldNotBubbleUp_invalidMetadata() {
+    public void shouldBubbleUp_false_invalidMetadata() {
         ensureStateForBubbleUp();
 
         NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -466,18 +529,24 @@
         assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(entry)).isFalse();
     }
 
+    /**
+     * If the notification can't heads up in general, it shouldn't bubble.
+     */
     @Test
-    public void shouldNotBubbleUp_suppressedInterruptions() {
+    public void shouldBubbleUp_false_alertAwakeCommonFalse() {
         ensureStateForBubbleUp();
 
-        // If the notification can't heads up in general, it shouldn't bubble.
-        mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
+        // Make alert common return false by pretending we're in VR mode
+        when(mPresenter.isDeviceInVrMode()).thenReturn(true);
 
         assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse();
     }
 
+    /**
+     * If the notification can't heads up in general, it shouldn't bubble.
+     */
     @Test
-    public void shouldNotBubbleUp_filteredOut() {
+    public void shouldBubbleUp_false_alertCommonFalse() {
         ensureStateForBubbleUp();
 
         // Make canAlertCommon false by saying it's filtered out
@@ -523,45 +592,20 @@
                 .build();
     }
 
-    private final NotificationInterruptSuppressor
-            mSuppressAwakeHeadsUp =
-            new NotificationInterruptSuppressor() {
-        @Override
-        public String getName() {
-            return "suppressAwakeHeadsUp";
-        }
+    /**
+     * Testable class overriding constructor.
+     */
+    public static class TestableNotificationInterruptionStateProvider extends
+            NotificationInterruptionStateProvider {
 
-        @Override
-        public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
-            return true;
+        TestableNotificationInterruptionStateProvider(Context context,
+                PowerManager powerManager, IDreamManager dreamManager,
+                AmbientDisplayConfiguration ambientDisplayConfiguration,
+                NotificationFilter notificationFilter,
+                StatusBarStateController statusBarStateController,
+                BatteryController batteryController) {
+            super(context, powerManager, dreamManager, ambientDisplayConfiguration,
+                    notificationFilter, batteryController, statusBarStateController);
         }
-    };
-
-    private final NotificationInterruptSuppressor
-            mSuppressAwakeInterruptions =
-            new NotificationInterruptSuppressor() {
-        @Override
-        public String getName() {
-            return "suppressAwakeInterruptions";
-        }
-
-        @Override
-        public boolean suppressAwakeInterruptions(NotificationEntry entry) {
-            return true;
-        }
-    };
-
-    private final NotificationInterruptSuppressor
-            mSuppressInterruptions =
-            new NotificationInterruptSuppressor() {
-        @Override
-        public String getName() {
-            return "suppressInterruptions";
-        }
-
-        @Override
-        public boolean suppressInterruptions(NotificationEntry entry) {
-            return true;
-        }
-    };
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 62f406f..1b0ed11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -22,6 +22,8 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 
+import com.android.internal.logging.InstanceId;
+
 /**
  * Convenience builder for {@link StatusBarNotification} since its constructor is terrifying.
  *
@@ -40,6 +42,7 @@
     private UserHandle mUser = UserHandle.of(0);
     private String mOverrideGroupKey;
     private long mPostTime;
+    private InstanceId mInstanceId;
 
     public SbnBuilder() {
     }
@@ -55,6 +58,7 @@
         mUser = source.getUser();
         mOverrideGroupKey = source.getOverrideGroupKey();
         mPostTime = source.getPostTime();
+        mInstanceId = source.getInstanceId();
     }
 
     public StatusBarNotification build() {
@@ -71,7 +75,7 @@
             notification.setBubbleMetadata(mBubbleMetadata);
         }
 
-        return new StatusBarNotification(
+        StatusBarNotification result = new StatusBarNotification(
                 mPkg,
                 mOpPkg,
                 mId,
@@ -82,6 +86,10 @@
                 mUser,
                 mOverrideGroupKey,
                 mPostTime);
+        if (mInstanceId != null) {
+            result.setInstanceId(mInstanceId);
+        }
+        return result;
     }
 
     public SbnBuilder setPkg(String pkg) {
@@ -175,4 +183,9 @@
         mBubbleMetadata = data;
         return this;
     }
+
+    public SbnBuilder setInstanceId(InstanceId instanceId) {
+        mInstanceId = instanceId;
+        return this;
+    }
 }
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 92a9080..261dc82 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
@@ -26,6 +26,7 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 
+import com.android.internal.logging.InstanceId;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SbnBuilder;
 
@@ -141,6 +142,11 @@
         return this;
     }
 
+    public NotificationEntryBuilder setInstanceId(InstanceId instanceId) {
+        mSbnBuilder.setInstanceId(instanceId);
+        return this;
+    }
+
     /* Delegated to Notification.Builder (via SbnBuilder) */
 
     public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d826ce1..d39b2c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.statusbar.notification.logging;
 
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+
 import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -34,6 +37,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.InstanceId;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.SysuiTestCase;
@@ -43,6 +47,7 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -81,9 +86,10 @@
 
     private NotificationEntry mEntry;
     private TestableNotificationLogger mLogger;
-    private NotificationEntryListener mNotificationEntryListener;
     private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+    private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
+            new NotificationPanelLoggerFake();
 
     @Before
     public void setUp() {
@@ -97,6 +103,7 @@
                 .setUid(TEST_UID)
                 .setNotification(new Notification())
                 .setUser(UserHandle.CURRENT)
+                .setInstanceId(InstanceId.fakeInstanceId(1))
                 .build();
         mEntry.setRow(mRow);
 
@@ -105,7 +112,6 @@
                 mExpansionStateLogger);
         mLogger.setUpWithContainer(mListContainer);
         verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
-        mNotificationEntryListener = mEntryListenerCaptor.getValue();
     }
 
     @Test
@@ -164,6 +170,41 @@
         verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
     }
 
+    @Test
+    public void testLogPanelShownOnLoggingStart() {
+        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+        mLogger.startNotificationLogging();
+        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+        assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+        assertEquals(TEST_PACKAGE_NAME, n.packageName);
+        assertEquals(TEST_UID, n.uid);
+        assertEquals(1, n.instanceId);
+        assertEquals(false, n.isGroupSummary);
+        assertEquals(1 + BUCKET_ALERTING, n.section);
+    }
+
+    @Test
+    public void testLogPanelShownHandlesNullInstanceIds() {
+        // Construct a NotificationEntry like mEntry, but with a null instance id.
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setNotification(new Notification())
+                .setUser(UserHandle.CURRENT)
+                .build();
+        entry.setRow(mRow);
+
+        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
+        mLogger.startNotificationLogging();
+        assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+        assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+        Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+        assertEquals(0, n.instanceId);
+    }
+
     private class TestableNotificationLogger extends NotificationLogger {
 
         TestableNotificationLogger(NotificationListener notificationListener,
@@ -173,7 +214,7 @@
                 IStatusBarService barService,
                 ExpansionStateLogger expansionStateLogger) {
             super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
-                    expansionStateLogger);
+                    expansionStateLogger, mNotificationPanelLoggerFake);
             mBarService = barService;
             // Make this on the current thread so we can wait for it during tests.
             mHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
new file mode 100644
index 0000000..7e97629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -0,0 +1,51 @@
+/*
+ * 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.logging;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationPanelLoggerFake implements NotificationPanelLogger {
+    private List<CallRecord> mCalls = new ArrayList<>();
+
+    List<CallRecord> getCalls() {
+        return mCalls;
+    }
+
+    CallRecord get(int index) {
+        return mCalls.get(index);
+    }
+
+    @Override
+    public void logPanelShown(boolean isLockscreen,
+            List<NotificationEntry> visibleNotifications) {
+        mCalls.add(new CallRecord(isLockscreen,
+                NotificationPanelLogger.toNotificationProto(visibleNotifications)));
+    }
+
+    public static class CallRecord {
+        public boolean isLockscreen;
+        public Notifications.NotificationList list;
+        CallRecord(boolean isLockscreen, Notifications.NotificationList list) {
+            this.isLockscreen = isLockscreen;
+            this.list = list;
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index a21a047..5d0349d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -56,12 +56,12 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -108,7 +108,7 @@
     @Mock private NotificationEntryListener mEntryListener;
     @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
     @Mock private HeadsUpManager mHeadsUpManager;
-    @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
+    @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationGutsManager mGutsManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index b9c5b7c..1e4df27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -67,10 +67,10 @@
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -183,7 +183,7 @@
                 mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
                 mock(NotificationLockscreenUserManager.class),
                 mKeyguardStateController,
-                mock(NotificationInterruptStateProvider.class), mock(MetricsLogger.class),
+                mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
                 mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor,
                 mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags,
                 mNotifPipeline, mNotifCollection)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index 318e9b8..b9d2d22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -16,9 +16,8 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.Notification;
@@ -36,7 +35,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.logging.testing.FakeMetricsLogger;
-import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -50,12 +48,12 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -64,7 +62,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
 
@@ -75,9 +72,6 @@
 
 
     private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
-    private NotificationInterruptStateProvider mNotificationInterruptStateProvider =
-            mock(NotificationInterruptStateProvider.class);
-    private NotificationInterruptSuppressor mInterruptSuppressor;
     private CommandQueue mCommandQueue;
     private FakeMetricsLogger mMetricsLogger;
     private ShadeController mShadeController = mock(ShadeController.class);
@@ -101,11 +95,11 @@
         mDependency.injectMockDependency(NotificationViewHierarchyManager.class);
         mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
         mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
+        mDependency.injectMockDependency(NotificationInterruptionStateProvider.class);
         mDependency.injectMockDependency(NotificationMediaManager.class);
         mDependency.injectMockDependency(VisualStabilityManager.class);
         mDependency.injectMockDependency(NotificationGutsManager.class);
         mDependency.injectMockDependency(NotificationShadeWindowController.class);
-        mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
         NotificationEntryManager entryManager =
                 mDependency.injectMockDependency(NotificationEntryManager.class);
         when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
@@ -113,25 +107,18 @@
         NotificationShadeWindowView notificationShadeWindowView =
                 mock(NotificationShadeWindowView.class);
         when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
-
         mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
                 mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class),
                 notificationShadeWindowView, mock(NotificationListContainerViewGroup.class),
                 mock(DozeScrimController.class), mock(ScrimController.class),
                 mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
-                mock(KeyguardStateController.class),
+                mock(NotificationAlertingManager.class), mock(KeyguardStateController.class),
                 mock(KeyguardIndicationController.class), mStatusBar,
-                mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
-                mNotificationInterruptStateProvider);
-        mInitController.executePostInitTasks();
-        ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
-                ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
-        verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture());
-        mInterruptSuppressor = suppressorCaptor.getValue();
+                mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
     }
 
     @Test
-    public void testSuppressHeadsUp_disabledStatusBar() {
+    public void testHeadsUp_disabledStatusBar() {
         Notification n = new Notification.Builder(getContext(), "a").build();
         NotificationEntry entry = new NotificationEntryBuilder()
                 .setPkg("a")
@@ -143,12 +130,12 @@
                 false /* animate */);
         TestableLooper.get(this).processAllMessages();
 
-        assertTrue("The panel should suppress heads up while disabled",
-                mInterruptSuppressor.suppressAwakeHeadsUp(entry));
+        assertFalse("The panel shouldn't allow heads up while disabled",
+                mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
     }
 
     @Test
-    public void testSuppressHeadsUp_disabledNotificationShade() {
+    public void testHeadsUp_disabledNotificationShade() {
         Notification n = new Notification.Builder(getContext(), "a").build();
         NotificationEntry entry = new NotificationEntryBuilder()
                 .setPkg("a")
@@ -160,39 +147,8 @@
                 false /* animate */);
         TestableLooper.get(this).processAllMessages();
 
-        assertTrue("The panel should suppress interruptions while notification shade "
-                        + "disabled",
-                mInterruptSuppressor.suppressAwakeHeadsUp(entry));
-    }
-
-    @Test
-    public void testSuppressInterruptions_vrMode() {
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg("a")
-                .setOpPkg("a")
-                .setTag("a")
-                .setNotification(n)
-                .build();
-        mStatusBarNotificationPresenter.mVrMode = true;
-
-        assertTrue("Vr mode should suppress interruptions",
-                mInterruptSuppressor.suppressAwakeInterruptions(entry));
-    }
-
-    @Test
-    public void testSuppressInterruptions_statusBarAlertsDisabled() {
-        Notification n = new Notification.Builder(getContext(), "a").build();
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg("a")
-                .setOpPkg("a")
-                .setTag("a")
-                .setNotification(n)
-                .build();
-        when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true);
-
-        assertTrue("StatusBar alerts disabled shouldn't allow interruptions",
-                mInterruptSuppressor.suppressInterruptions(entry));
+        assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
+                mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
     }
 
     @Test
@@ -216,3 +172,4 @@
         }
     }
 }
+
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index d9f4d4b..e407927 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -42,7 +42,7 @@
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
+import android.content.Context;
 import android.content.IntentFilter;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.hardware.fingerprint.FingerprintManager;
@@ -109,18 +109,20 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SuperStatusBarViewFactory;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
-import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -128,7 +130,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -160,7 +161,7 @@
     private StatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
     private PowerManager mPowerManager;
-    private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider;
+    private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
 
     @Mock private NotificationsController mNotificationsController;
     @Mock private LightBarController mLightBarController;
@@ -178,6 +179,7 @@
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private BiometricUnlockController mBiometricUnlockController;
+    @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
@@ -190,9 +192,10 @@
     @Mock private StatusBarNotificationPresenter mNotificationPresenter;
     @Mock private NotificationEntryListener mEntryListener;
     @Mock private NotificationFilter mNotificationFilter;
-    @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
+    @Mock private NotificationAlertingManager mNotificationAlertingManager;
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
     @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private AssistManager mAssistManager;
@@ -260,12 +263,10 @@
         mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
                 Handler.createAsync(Looper.myLooper()));
 
-        mNotificationInterruptStateProvider =
-                new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
-                        mPowerManager,
+        mNotificationInterruptionStateProvider =
+                new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
                         mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
-                        mStatusBarStateController, mBatteryController, mHeadsUpManager,
-                        new Handler(TestableLooper.get(this).getLooper()));
+                        mStatusBarStateController, mBatteryController);
 
         mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -273,7 +274,7 @@
         mMetricsLogger = new FakeMetricsLogger();
         NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
                 mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController,
-                mExpansionStateLogger);
+                mExpansionStateLogger, new NotificationPanelLoggerFake());
         notificationLogger.setVisibilityReporter(mock(Runnable.class));
 
         when(mCommandQueue.asBinder()).thenReturn(new Binder());
@@ -298,6 +299,9 @@
             return null;
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
+        mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
+                mHeadsUpManager, mHeadsUpSuppressor);
+
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
 
         WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
@@ -344,9 +348,10 @@
                 ),
                 mNotificationGutsManager,
                 notificationLogger,
-                mNotificationInterruptStateProvider,
+                mNotificationInterruptionStateProvider,
                 mNotificationViewHierarchyManager,
                 mKeyguardViewMediator,
+                mNotificationAlertingManager,
                 new DisplayMetrics(),
                 mMetricsLogger,
                 mUiBgExecutor,
@@ -557,6 +562,7 @@
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -572,7 +578,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+        assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -581,6 +587,7 @@
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a")
                 .setGroup("a")
@@ -596,7 +603,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+        assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -605,6 +612,7 @@
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a").build();
 
@@ -617,7 +625,7 @@
                 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK)
                 .build();
 
-        assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+        assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -626,6 +634,7 @@
         when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
         when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
         when(mDreamManager.isDreaming()).thenReturn(false);
+        when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
 
         Notification n = new Notification.Builder(getContext(), "a").build();
 
@@ -637,7 +646,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
+        assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -863,21 +872,19 @@
         verify(mDozeServiceHost).setDozeSuppressed(false);
     }
 
-    public static class TestableNotificationInterruptStateProviderImpl extends
-            NotificationInterruptStateProviderImpl {
+    public static class TestableNotificationInterruptionStateProvider extends
+            NotificationInterruptionStateProvider {
 
-        TestableNotificationInterruptStateProviderImpl(
-                ContentResolver contentResolver,
+        TestableNotificationInterruptionStateProvider(
+                Context context,
                 PowerManager powerManager,
                 IDreamManager dreamManager,
                 AmbientDisplayConfiguration ambientDisplayConfiguration,
                 NotificationFilter filter,
                 StatusBarStateController controller,
-                BatteryController batteryController,
-                HeadsUpManager headsUpManager,
-                Handler mainHandler) {
-            super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
-                    batteryController, controller, headsUpManager, mainHandler);
+                BatteryController batteryController) {
+            super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter,
+                    batteryController, controller);
             mUseHeadsUp = true;
         }
     }
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5b73dd5..2fbba68 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -62,26 +62,14 @@
     apex_available: ["com.android.tethering"],
 }
 
-droidstubs {
-    name: "framework-tethering-stubs-sources",
-    defaults: ["framework-module-stubs-defaults-module_libs_api"],
+stubs_defaults {
+    name: "framework-tethering-stubs-defaults",
     srcs: [
         "src/android/net/TetheredClient.java",
         "src/android/net/TetheringManager.java",
         "src/android/net/TetheringConstants.java",
     ],
-    libs: [
-        "tethering-aidl-interfaces-java",
-        "framework-all",
-    ],
-    sdk_version: "core_platform",
-}
-
-java_library {
-    name: "framework-tethering-stubs",
-    srcs: [":framework-tethering-stubs-sources"],
-    libs: ["framework-all"],
-    sdk_version: "core_platform",
+    libs: ["tethering-aidl-interfaces-java"],
 }
 
 filegroup {
@@ -101,3 +89,53 @@
     ],
     path: "src"
 }
+
+droidstubs {
+    name: "framework-tethering-stubs-srcs-publicapi",
+    defaults: [
+        "framework-module-stubs-defaults-publicapi",
+        "framework-tethering-stubs-defaults",
+    ],
+}
+
+droidstubs {
+    name: "framework-tethering-stubs-srcs-systemapi",
+    defaults: [
+        "framework-module-stubs-defaults-systemapi",
+        "framework-tethering-stubs-defaults",
+    ],
+}
+
+droidstubs {
+    name: "framework-tethering-api-module_libs_api",
+    defaults: [
+        "framework-module-api-defaults-module_libs_api",
+        "framework-tethering-stubs-defaults",
+    ],
+}
+
+droidstubs {
+    name: "framework-tethering-stubs-srcs-module_libs_api",
+    defaults: [
+        "framework-module-stubs-defaults-module_libs_api",
+        "framework-tethering-stubs-defaults",
+    ],
+}
+
+java_library {
+    name: "framework-tethering-stubs-publicapi",
+    srcs: [":framework-tethering-stubs-srcs-publicapi"],
+    sdk_version: "current",
+}
+
+java_library {
+    name: "framework-tethering-stubs-systemapi",
+    srcs: [":framework-tethering-stubs-srcs-systemapi"],
+    sdk_version: "system_current",
+}
+
+java_library {
+    name: "framework-tethering-stubs-module_libs_api",
+    srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
+    sdk_version: "module_current",
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index a554193..b4e3ba4 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -35,4 +35,5 @@
     void onConfigurationChanged(in TetheringConfigurationParcel config);
     void onTetherStatesChanged(in TetherStatesParcel states);
     void onTetherClientsChanged(in List<TetheredClient> clients);
+    void onOffloadStatusChanged(int status);
 }
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
index c064aa4..253eacb 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -31,4 +31,5 @@
     TetheringConfigurationParcel config;
     TetherStatesParcel states;
     List<TetheredClient> tetheredClients;
-}
\ No newline at end of file
+    int offloadStatus;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index fd9f713..7f831ce 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -18,6 +18,7 @@
 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
 
 import android.Manifest;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -34,6 +35,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -172,6 +175,23 @@
     public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
     public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = false, value = {
+            TETHER_HARDWARE_OFFLOAD_STOPPED,
+            TETHER_HARDWARE_OFFLOAD_STARTED,
+            TETHER_HARDWARE_OFFLOAD_FAILED,
+    })
+    public @interface TetherOffloadStatus {
+    }
+
+    /** Tethering offload status is stopped. */
+    public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0;
+    /** Tethering offload status is started. */
+    public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1;
+    /** Fail to start tethering offload. */
+    public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2;
+
     /**
      * Create a TetheringManager object for interacting with the tethering service.
      *
@@ -378,6 +398,9 @@
         @Override
         public void onTetherClientsChanged(List<TetheredClient> clients) { }
 
+        @Override
+        public void onOffloadStatusChanged(int status) { }
+
         public void waitForStarted() {
             mWaitForCallback.block(DEFAULT_TIMEOUT_MS);
             throwIfPermissionFailure(mError);
@@ -802,6 +825,14 @@
          * @param clients The new set of tethered clients; the collection is not ordered.
          */
         public void onClientsChanged(@NonNull Collection<TetheredClient> clients) {}
+
+        /**
+         * Called when tethering offload status changes.
+         *
+         * <p>This will be called immediately after the callback is registered.
+         * @param status The offload status.
+         */
+        public void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
     }
 
     /**
@@ -925,6 +956,7 @@
                         maybeSendTetherableIfacesChangedCallback(parcel.states);
                         maybeSendTetheredIfacesChangedCallback(parcel.states);
                         callback.onClientsChanged(parcel.tetheredClients);
+                        callback.onOffloadStatusChanged(parcel.offloadStatus);
                     });
                 }
 
@@ -960,6 +992,11 @@
                 public void onTetherClientsChanged(final List<TetheredClient> clients) {
                     executor.execute(() -> callback.onClientsChanged(clients));
                 }
+
+                @Override
+                public void onOffloadStatusChanged(final int status) {
+                    executor.execute(() -> callback.onOffloadStatusChanged(status));
+                }
             };
             getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
             mTetheringEventCallbacks.put(callback, remoteCallback);
@@ -1131,6 +1168,25 @@
     public boolean isTetheringSupported() {
         final String callerPkg = mContext.getOpPackageName();
 
+        return isTetheringSupported(callerPkg);
+    }
+
+    /**
+     * Check if the device allows for tethering. It may be disabled via {@code ro.tether.denied}
+     * system property, Settings.TETHER_SUPPORTED or due to device configuration. This is useful
+     * for system components that query this API on behalf of an app. In particular, Bluetooth
+     * has @UnsupportedAppUsage calls that will let apps turn on bluetooth tethering if they have
+     * the right permissions, but such an app needs to know whether it can (permissions as well
+     * as support from the device) turn on tethering in the first place to show the appropriate UI.
+     *
+     * @param callerPkg The caller package name, if it is not matching the calling uid,
+     *       SecurityException would be thrown.
+     * @return a boolean - {@code true} indicating Tethering is supported.
+     * @hide
+     */
+    @SystemApi(client = MODULE_LIBRARIES)
+    public boolean isTetheringSupported(@NonNull final String callerPkg) {
+
         final RequestDispatcher dispatcher = new RequestDispatcher();
         final int ret = dispatcher.waitForResult((connector, listener) -> {
             try {
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 3acc766..38f8609 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -810,7 +810,7 @@
                     rule.dstMac.toByteArray());
             mIpv6ForwardingRules.put(rule.address, rule);
         } catch (RemoteException | ServiceSpecificException e) {
-            Log.e(TAG, "Could not add IPv6 downstream rule: " + e);
+            mLog.e("Could not add IPv6 downstream rule: ", e);
         }
     }
 
@@ -821,10 +821,17 @@
                 mIpv6ForwardingRules.remove(rule.address);
             }
         } catch (RemoteException | ServiceSpecificException e) {
-            Log.e(TAG, "Could not remove IPv6 downstream rule: " + e);
+            mLog.e("Could not remove IPv6 downstream rule: ", e);
         }
     }
 
+    private void clearIpv6ForwardingRules() {
+        for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) {
+            removeIpv6ForwardingRule(rule, false /*removeFromMap*/);
+        }
+        mIpv6ForwardingRules.clear();
+    }
+
     // Convenience method to replace a rule with the same rule on a new upstream interface.
     // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions.
     // Relies on the fact that rules are in a map indexed by IP address.
@@ -837,6 +844,12 @@
     // changes or if a neighbor event is received.
     private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
             NeighborEvent e) {
+        // If we no longer have an upstream, clear forwarding rules and do nothing else.
+        if (upstreamIfindex == 0) {
+            clearIpv6ForwardingRules();
+            return;
+        }
+
         // If the upstream interface has changed, remove all rules and re-add them with the new
         // upstream interface.
         if (prevUpstreamIfindex != upstreamIfindex) {
@@ -846,13 +859,14 @@
         }
 
         // If we're here to process a NeighborEvent, do so now.
+        // mInterfaceParams must be non-null or the event would not have arrived.
         if (e == null) return;
         if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress()
                 || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) {
             return;
         }
 
-        Ipv6ForwardingRule rule = new Ipv6ForwardingRule(mLastIPv6UpstreamIfindex,
+        Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex,
                 mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr,
                 e.macAddr);
         if (e.isValid()) {
@@ -1095,6 +1109,7 @@
 
             for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
             mUpstreamIfaceSet = null;
+            clearIpv6ForwardingRules();
         }
 
         private void cleanupUpstreamInterface(String upstreamIface) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
index cc36f4a..a402ffa 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java
@@ -288,10 +288,18 @@
 
         @Override
         public void setLimit(String iface, long quotaBytes) {
-            mLog.i("setLimit: " + iface + "," + quotaBytes);
             // Listen for all iface is necessary since upstream might be changed after limit
             // is set.
             mHandler.post(() -> {
+                final Long curIfaceQuota = mInterfaceQuotas.get(iface);
+
+                // If the quota is set to unlimited, the value set to HAL is Long.MAX_VALUE,
+                // which is ~8.4 x 10^6 TiB, no one can actually reach it. Thus, it is not
+                // useful to set it multiple times.
+                // Otherwise, the quota needs to be updated to tell HAL to re-count from now even
+                // if the quota is the same as the existing one.
+                if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
+
                 if (quotaBytes == QUOTA_UNLIMITED) {
                     mInterfaceQuotas.remove(iface);
                 } else {
@@ -323,7 +331,6 @@
 
         @Override
         public void requestStatsUpdate(int token) {
-            mLog.i("requestStatsUpdate: " + token);
             // Do not attempt to update stats by querying the offload HAL
             // synchronously from a different thread than the Handler thread. http://b/64771555.
             mHandler.post(() -> {
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 ca74430..f89da84 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -44,6 +44,9 @@
 import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
 import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
 import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
 import static android.net.util.TetheringMessageBase.BASE_MASTER;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -220,6 +223,7 @@
     private final UserRestrictionActionListener mTetheringRestriction;
     private final ActiveDataSubIdListener mActiveDataSubIdListener;
     private final ConnectedClientsTracker mConnectedClientsTracker;
+    private final TetheringThreadExecutor mExecutor;
     private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
     // All the usage of mTetheringEventCallback should run in the same thread.
     private ITetheringEventCallback mTetheringEventCallback = null;
@@ -236,6 +240,7 @@
     private TetherStatesParcel mTetherStatesParcel;
     private boolean mDataSaverEnabled = false;
     private String mWifiP2pTetherInterface = null;
+    private int mOffloadStatus = TETHER_HARDWARE_OFFLOAD_STOPPED;
 
     @GuardedBy("mPublicSync")
     private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
@@ -296,8 +301,8 @@
         final UserManager userManager = (UserManager) mContext.getSystemService(
                 Context.USER_SERVICE);
         mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
-        final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler);
-        mActiveDataSubIdListener = new ActiveDataSubIdListener(executor);
+        mExecutor = new TetheringThreadExecutor(mHandler);
+        mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
 
         // Load tethering configuration.
         updateConfiguration();
@@ -315,9 +320,7 @@
 
         final WifiManager wifiManager = getWifiManager();
         if (wifiManager != null) {
-            wifiManager.registerSoftApCallback(
-                  mHandler::post /* executor */,
-                  new TetheringSoftApCallback());
+            wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
         }
     }
 
@@ -606,14 +609,17 @@
                 Context.ETHERNET_SERVICE);
         synchronized (mPublicSync) {
             if (enable) {
+                if (mEthernetCallback != null) return TETHER_ERROR_NO_ERROR;
+
                 mEthernetCallback = new EthernetCallback();
-                mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback);
+                mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
             } else {
-                if (mConfiguredEthernetIface != null) {
-                    stopEthernetTetheringLocked();
+                stopEthernetTetheringLocked();
+                if (mEthernetCallback != null) {
                     mEthernetIfaceRequest.release();
+                    mEthernetCallback = null;
+                    mEthernetIfaceRequest = null;
                 }
-                mEthernetCallback = null;
             }
         }
         return TETHER_ERROR_NO_ERROR;
@@ -1899,12 +1905,15 @@
         // OffloadController implementation.
         class OffloadWrapper {
             public void start() {
-                mOffloadController.start();
+                final int status = mOffloadController.start() ? TETHER_HARDWARE_OFFLOAD_STARTED
+                        : TETHER_HARDWARE_OFFLOAD_FAILED;
+                updateOffloadStatus(status);
                 sendOffloadExemptPrefixes();
             }
 
             public void stop() {
                 mOffloadController.stop();
+                updateOffloadStatus(TETHER_HARDWARE_OFFLOAD_STOPPED);
             }
 
             public void updateUpstreamNetworkState(UpstreamNetworkState ns) {
@@ -1965,6 +1974,13 @@
 
                 mOffloadController.setLocalPrefixes(localPrefixes);
             }
+
+            private void updateOffloadStatus(final int newStatus) {
+                if (newStatus == mOffloadStatus) return;
+
+                mOffloadStatus = newStatus;
+                reportOffloadStatusChanged(mOffloadStatus);
+            }
         }
     }
 
@@ -1999,6 +2015,7 @@
             parcel.tetheredClients = hasListPermission
                     ? mConnectedClientsTracker.getLastTetheredClients()
                     : Collections.emptyList();
+            parcel.offloadStatus = mOffloadStatus;
             try {
                 callback.onCallbackStarted(parcel);
             } catch (RemoteException e) {
@@ -2093,6 +2110,21 @@
         }
     }
 
+    private void reportOffloadStatusChanged(final int status) {
+        final int length = mTetheringEventCallbacks.beginBroadcast();
+        try {
+            for (int i = 0; i < length; i++) {
+                try {
+                    mTetheringEventCallbacks.getBroadcastItem(i).onOffloadStatusChanged(status);
+                } catch (RemoteException e) {
+                    // Not really very much to do here.
+                }
+            }
+        } finally {
+            mTetheringEventCallbacks.finishBroadcast();
+        }
+    }
+
     void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
         // Binder.java closes the resource for us.
         @SuppressWarnings("resource")
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 33b3558..948266d 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -43,6 +43,7 @@
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doAnswer;
@@ -546,9 +547,9 @@
         reset(mNetd);
 
         // Link-local and multicast neighbors are ignored.
-        recvNewNeigh(notMyIfindex, neighLL, NUD_REACHABLE, macA);
+        recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA);
         verifyNoMoreInteractions(mNetd);
-        recvNewNeigh(notMyIfindex, neighMC, NUD_REACHABLE, macA);
+        recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA);
         verifyNoMoreInteractions(mNetd);
 
         // A neighbor that is no longer valid causes the rule to be removed.
@@ -578,6 +579,52 @@
                 eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
         inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
                 eq(neighB.getAddress()));
+        reset(mNetd);
+
+        // When the upstream is lost, rules are removed.
+        dispatchTetherConnectionChanged(null, null);
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
+                eq(neighA.getAddress()));
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
+                eq(neighB.getAddress()));
+        reset(mNetd);
+
+        // If the upstream is IPv4-only, no rules are added.
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+        reset(mNetd);
+        recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        verifyNoMoreInteractions(mNetd);
+
+        // Rules can be added again once upstream IPv6 connectivity is available.
+        lp.setInterfaceName(UPSTREAM_IFACE);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
+        recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+                eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+        verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(),
+                eq(neighA.getAddress()), any(), any());
+
+        // If upstream IPv6 connectivity is lost, rules are removed.
+        reset(mNetd);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, null);
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+
+        // When the interface goes down, rules are removed.
+        lp.setInterfaceName(UPSTREAM_IFACE);
+        dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
+        recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
+        recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
+        verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+                eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+        verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
+                eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+        reset(mNetd);
+
+        mIpServer.stop();
+        mLooper.dispatchAll();
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+        verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+        reset(mNetd);
     }
 
     private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
@@ -624,16 +671,15 @@
      * @param v6lp IPv6 LinkProperties of the upstream interface, or null for an IPv4-only upstream.
      */
     private void dispatchTetherConnectionChanged(String upstreamIface, LinkProperties v6lp) {
-        mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
-                new InterfaceSet(upstreamIface));
-        if (v6lp != null) {
-            mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp);
-        }
+        dispatchTetherConnectionChanged(upstreamIface);
+        mIpServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, v6lp);
         mLooper.dispatchAll();
     }
 
     private void dispatchTetherConnectionChanged(String upstreamIface) {
-        dispatchTetherConnectionChanged(upstreamIface, null);
+        final InterfaceSet ifs = (upstreamIface != null) ? new InterfaceSet(upstreamIface) : null;
+        mIpServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifs);
+        mLooper.dispatchAll();
     }
 
     private void assertIPv4AddressAndDirectlyConnectedRoute(LinkProperties lp) {
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 f2074bd..af7ad66 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
@@ -28,11 +28,15 @@
 import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
 import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
 import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
 import static android.net.TetheringManager.TETHERING_NCM;
 import static android.net.TetheringManager.TETHERING_USB;
 import static android.net.TetheringManager.TETHERING_WIFI;
 import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
 import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
+import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -75,6 +79,8 @@
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
 import android.net.ConnectivityManager;
+import android.net.EthernetManager;
+import android.net.EthernetManager.TetheredInterfaceRequest;
 import android.net.INetd;
 import android.net.ITetheringEventCallback;
 import android.net.InetAddresses;
@@ -166,6 +172,7 @@
     @Mock private Context mContext;
     @Mock private NetworkStatsManager mStatsManager;
     @Mock private OffloadHardwareInterface mOffloadHardwareInterface;
+    @Mock private OffloadHardwareInterface.ForwardedStats mForwardedStats;
     @Mock private Resources mResources;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private UsbManager mUsbManager;
@@ -180,6 +187,7 @@
     @Mock private UserManager mUserManager;
     @Mock private NetworkRequest mNetworkRequest;
     @Mock private ConnectivityManager mCm;
+    @Mock private EthernetManager mEm;
 
     private final MockIpServerDependencies mIpServerDependencies =
             spy(new MockIpServerDependencies());
@@ -232,6 +240,7 @@
             if (Context.USER_SERVICE.equals(name)) return mUserManager;
             if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager;
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
+            if (Context.ETHERNET_SERVICE.equals(name)) return mEm;
             return super.getSystemService(name);
         }
 
@@ -458,6 +467,9 @@
         mInterfaceConfiguration.flags = new String[0];
         when(mRouterAdvertisementDaemon.start())
                 .thenReturn(true);
+        initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */,
+                0 /* defaultDisabled */);
+        when(mOffloadHardwareInterface.getForwardedStats(any())).thenReturn(mForwardedStats);
 
         mServiceContext = new TestContext(mContext);
         when(mContext.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(null);
@@ -1131,6 +1143,7 @@
         private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs =
                 new ArrayList<>();
         private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
+        private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
 
         // This function will remove the recorded callbacks, so it must be called once for
         // each callback. If this is called after multiple callback, the order matters.
@@ -1166,6 +1179,11 @@
             assertNoConfigChangeCallback();
         }
 
+        public void expectOffloadStatusChanged(final int expectedStatus) {
+            assertOffloadStatusChangedCallback();
+            assertEquals(mOffloadStatus.remove(0), new Integer(expectedStatus));
+        }
+
         public TetherStatesParcel pollTetherStatesChanged() {
             assertStateChangeCallback();
             return mTetherStates.remove(0);
@@ -1192,10 +1210,16 @@
         }
 
         @Override
+        public void onOffloadStatusChanged(final int status) {
+            mOffloadStatus.add(status);
+        }
+
+        @Override
         public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
             mActualUpstreams.add(parcel.upstreamNetwork);
             mTetheringConfigs.add(parcel.config);
             mTetherStates.add(parcel.states);
+            mOffloadStatus.add(parcel.offloadStatus);
         }
 
         @Override
@@ -1217,6 +1241,10 @@
             assertFalse(mTetherStates.isEmpty());
         }
 
+        public void assertOffloadStatusChangedCallback() {
+            assertFalse(mOffloadStatus.isEmpty());
+        }
+
         public void assertNoCallback() {
             assertNoUpstreamChangeCallback();
             assertNoConfigChangeCallback();
@@ -1265,6 +1293,7 @@
                 mTethering.getTetheringConfiguration().toStableParcelable());
         TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
         assertTetherStatesNotNullButEmpty(tetherState);
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
         // 2. Enable wifi tethering.
         UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
         when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
@@ -1282,6 +1311,7 @@
         tetherState = callback.pollTetherStatesChanged();
         assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
         callback.expectUpstreamChanged(upstreamState.network);
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
 
         // 3. Register second callback.
         mTethering.registerTetheringEventCallback(callback2);
@@ -1291,6 +1321,7 @@
                 mTethering.getTetheringConfiguration().toStableParcelable());
         tetherState = callback2.pollTetherStatesChanged();
         assertEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
+        callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
 
         // 4. Unregister first callback and disable wifi tethering
         mTethering.unregisterTetheringEventCallback(callback);
@@ -1302,10 +1333,59 @@
         assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
         mLooper.dispatchAll();
         callback2.expectUpstreamChanged(new Network[] {null});
+        callback2.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
         callback.assertNoCallback();
     }
 
     @Test
+    public void testReportFailCallbackIfOffloadNotSupported() throws Exception {
+        final UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
+        TestTetheringEventCallback callback = new TestTetheringEventCallback();
+        mTethering.registerTetheringEventCallback(callback);
+        mLooper.dispatchAll();
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+
+        // 1. Offload fail if no OffloadConfig.
+        initOffloadConfiguration(false /* offloadConfig */, true /* offloadControl */,
+                0 /* defaultDisabled */);
+        runUsbTethering(upstreamState);
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+        runStopUSBTethering();
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+        reset(mUsbManager);
+        // 2. Offload fail if no OffloadControl.
+        initOffloadConfiguration(true /* offloadConfig */, false /* offloadControl */,
+                0 /* defaultDisabled */);
+        runUsbTethering(upstreamState);
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+        runStopUSBTethering();
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+        reset(mUsbManager);
+        // 3. Offload fail if disabled by settings.
+        initOffloadConfiguration(true /* offloadConfig */, true /* offloadControl */,
+                1 /* defaultDisabled */);
+        runUsbTethering(upstreamState);
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_FAILED);
+        runStopUSBTethering();
+        callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
+    }
+
+    private void runStopUSBTethering() {
+        mTethering.stopTethering(TETHERING_USB);
+        mLooper.dispatchAll();
+        mTethering.interfaceRemoved(TEST_USB_IFNAME);
+        mLooper.dispatchAll();
+    }
+
+    private void initOffloadConfiguration(final boolean offloadConfig,
+            final boolean offloadControl, final int defaultDisabled) {
+        when(mOffloadHardwareInterface.initOffloadConfig()).thenReturn(offloadConfig);
+        when(mOffloadHardwareInterface.initOffloadControl(any())).thenReturn(offloadControl);
+        when(mOffloadHardwareInterface.getDefaultTetherOffloadDisabled()).thenReturn(
+                defaultDisabled);
+    }
+
+    @Test
     public void testMultiSimAware() throws Exception {
         final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
         assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.activeDataSubId);
@@ -1316,6 +1396,24 @@
         assertEquals(fakeSubId, newConfig.activeDataSubId);
     }
 
+    @Test
+    public void testNoDuplicatedEthernetRequest() throws Exception {
+        final TetheredInterfaceRequest mockRequest = mock(TetheredInterfaceRequest.class);
+        when(mEm.requestTetheredInterface(any(), any())).thenReturn(mockRequest);
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+        mLooper.dispatchAll();
+        verify(mEm, times(1)).requestTetheredInterface(any(), any());
+        mTethering.startTethering(createTetheringRquestParcel(TETHERING_ETHERNET), null);
+        mLooper.dispatchAll();
+        verifyNoMoreInteractions(mEm);
+        mTethering.stopTethering(TETHERING_ETHERNET);
+        mLooper.dispatchAll();
+        verify(mockRequest, times(1)).release();
+        mTethering.stopTethering(TETHERING_ETHERNET);
+        mLooper.dispatchAll();
+        verifyNoMoreInteractions(mEm);
+    }
+
     private void workingWifiP2pGroupOwner(
             boolean emulateInterfaceStatusChanged) throws Exception {
         if (emulateInterfaceStatusChanged) {
diff --git a/services/Android.bp b/services/Android.bp
index ef47867..c4be003 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -78,7 +78,7 @@
 
     libs: [
         "android.hidl.manager-V1.0-java",
-        "framework-tethering-stubs",
+        "framework-tethering-stubs-module_libs_api",
     ],
 
     plugins: [
diff --git a/services/api/current.txt b/services/api/current.txt
index 8c90165..9bbb3ef 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@
 
   public interface RuntimePermissionsPersistence {
     method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
-    method public void deleteAsUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle);
-    method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+    method public void deleteForUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
+    method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
   }
 
   public final class RuntimePermissionsState {
@@ -17,7 +17,7 @@
     field public static final int NO_VERSION = -1; // 0xffffffff
   }
 
-  public static class RuntimePermissionsState.PermissionState {
+  public static final class RuntimePermissionsState.PermissionState {
     ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
     method public int getFlags();
     method @NonNull public String getName();
@@ -30,9 +30,9 @@
 
   public interface RolesPersistence {
     method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
-    method public void deleteAsUser(@NonNull android.os.UserHandle);
-    method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle);
-    method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+    method public void deleteForUser(@NonNull android.os.UserHandle);
+    method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
+    method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
   }
 
   public final class RolesState {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 2420e69..e73f9ce 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -37,7 +37,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.autofill.Dataset;
-import android.service.autofill.InlinePresentation;
+import android.service.autofill.InlineAction;
 import android.service.autofill.augmented.AugmentedAutofillService;
 import android.service.autofill.augmented.IAugmentedAutofillService;
 import android.service.autofill.augmented.IFillCallback;
@@ -167,7 +167,7 @@
                             new IFillCallback.Stub() {
                                 @Override
                                 public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData,
-                                        @Nullable List<InlinePresentation> inlineActions) {
+                                        @Nullable List<InlineAction> inlineActions) {
                                     mCallbacks.resetLastResponse();
                                     maybeRequestShowInlineSuggestions(sessionId,
                                             inlineSuggestionsRequest, inlineSuggestionsData,
@@ -237,7 +237,7 @@
     private void maybeRequestShowInlineSuggestions(int sessionId,
             @Nullable InlineSuggestionsRequest request,
             @Nullable List<Dataset> inlineSuggestionsData,
-            @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId focusedId,
+            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId focusedId,
             @Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
             @NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
@@ -250,7 +250,7 @@
 
         final InlineSuggestionsResponse inlineSuggestionsResponse =
                 InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
-                        request, inlineSuggestionsData, inlineActions, focusedId, mContext,
+                        request, inlineSuggestionsData, inlineActions, focusedId,
                         dataset -> {
                             mCallbacks.logAugmentedAutofillSelected(sessionId,
                                     dataset.getId());
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index f14a7e9..538082d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -137,7 +137,6 @@
     private final Handler mHandler;
     private final Object mLock;
     private final AutoFillUI mUi;
-    private final Context mContext;
 
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
@@ -695,7 +694,6 @@
         mLock = lock;
         mUi = ui;
         mHandler = handler;
-        mContext = context;
         mRemoteFillService = serviceComponentName == null ? null
                 : new RemoteFillService(context, serviceComponentName, userId, this,
                         bindInstantServiceAllowed);
@@ -2680,10 +2678,10 @@
         InlineSuggestionsResponse inlineSuggestionsResponse =
                 InlineSuggestionFactory.createInlineSuggestionsResponse(
                         inlineSuggestionsRequest.get(),
-                        response, filterText, response.getInlineActions(), mCurrentViewId, mContext,
+                        response, filterText, response.getInlineActions(), mCurrentViewId,
                         this, () -> {
                             synchronized (mLock) {
-                                requestHideFillUi(mCurrentViewId);
+                                mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
                             }
                         }, remoteRenderService);
         if (inlineSuggestionsResponse == null) {
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 4cf4463..ee59d89 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -21,12 +21,13 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.Context;
+import android.content.IntentSender;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
 import android.service.autofill.IInlineSuggestionUiCallback;
+import android.service.autofill.InlineAction;
 import android.service.autofill.InlinePresentation;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -39,7 +40,6 @@
 import android.view.inputmethod.InlineSuggestionInfo;
 import android.view.inputmethod.InlineSuggestionsRequest;
 import android.view.inputmethod.InlineSuggestionsResponse;
-import android.widget.Toast;
 
 import com.android.internal.view.inline.IInlineContentCallback;
 import com.android.internal.view.inline.IInlineContentProvider;
@@ -73,8 +73,8 @@
     @Nullable
     public static InlineSuggestionsResponse createInlineSuggestionsResponse(
             @NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
-            @Nullable String filterText, @Nullable List<InlinePresentation> inlineActions,
-            @NonNull AutofillId autofillId, @NonNull Context context,
+            @Nullable String filterText, @Nullable List<InlineAction> inlineActions,
+            @NonNull AutofillId autofillId,
             @NonNull AutoFillUI.AutoFillUiCallback client, @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
         if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
@@ -97,7 +97,7 @@
                 response.getAuthentication() == null ? null : response.getInlinePresentation();
         return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
                 response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId,
-                context, onErrorCallback, onClickFactory, remoteRenderService);
+                onErrorCallback, onClickFactory, remoteRenderService);
     }
 
     /**
@@ -107,15 +107,14 @@
     @Nullable
     public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
             @NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
-            @Nullable List<InlinePresentation> inlineActions,
-            @NonNull AutofillId autofillId, @NonNull Context context,
+            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
             @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
             @NonNull Runnable onErrorCallback,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
         if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
         return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
                 datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
-                inlineActions, autofillId, context, onErrorCallback,
+                inlineActions, autofillId, onErrorCallback,
                 (dataset, datasetIndex) ->
                         inlineSuggestionUiCallback.autofill(dataset), remoteRenderService);
     }
@@ -125,9 +124,8 @@
             boolean isAugmented, @NonNull InlineSuggestionsRequest request,
             @Nullable List<Dataset> datasets, @Nullable String filterText,
             @Nullable InlinePresentation inlineAuthentication,
-            @Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId,
-            @NonNull Context context, @NonNull Runnable onErrorCallback,
-            @NonNull BiConsumer<Dataset, Integer> onClickFactory,
+            @Nullable List<InlineAction> inlineActions, @NonNull AutofillId autofillId,
+            @NonNull Runnable onErrorCallback, @NonNull BiConsumer<Dataset, Integer> onClickFactory,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService) {
 
         final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
@@ -169,14 +167,14 @@
 
             inlineSuggestions.add(inlineSuggestion);
         }
-        // We should only add inline actions if there is at least one suggestion.
-        if (!inlineSuggestions.isEmpty() && inlineActions != null) {
-            for (InlinePresentation inlinePresentation : inlineActions) {
-                final InlineSuggestion inlineAction = createInlineAction(isAugmented, context,
-                        mergedInlinePresentation(request, 0, inlinePresentation),
+        if (inlineActions != null) {
+            for (InlineAction inlineAction : inlineActions) {
+                final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented,
+                        mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()),
+                        inlineAction.getAction(),
                         remoteRenderService, onErrorCallback, request.getHostInputToken(),
                         request.getHostDisplayId());
-                inlineSuggestions.add(inlineAction);
+                inlineSuggestions.add(inlineActionSuggestion);
             }
         }
         return new InlineSuggestionsResponse(inlineSuggestions);
@@ -215,22 +213,30 @@
 
 
     private static InlineSuggestion createInlineAction(boolean isAugmented,
-            @NonNull Context context,
-            @NonNull InlinePresentation inlinePresentation,
+            @NonNull InlinePresentation presentation,
+            @NonNull IntentSender action,
             @Nullable RemoteInlineSuggestionRenderService remoteRenderService,
             @NonNull Runnable onErrorCallback, @Nullable IBinder hostInputToken,
             int displayId) {
         final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
-                inlinePresentation.getInlinePresentationSpec(),
+                presentation.getInlinePresentationSpec(),
                 isAugmented ? InlineSuggestionInfo.SOURCE_PLATFORM
                         : InlineSuggestionInfo.SOURCE_AUTOFILL,
-                inlinePresentation.getAutofillHints(),
-                InlineSuggestionInfo.TYPE_ACTION, inlinePresentation.isPinned());
+                presentation.getAutofillHints(), InlineSuggestionInfo.TYPE_ACTION,
+                presentation.isPinned());
         final Runnable onClickAction = () -> {
-            Toast.makeText(context, "icon clicked", Toast.LENGTH_SHORT).show();
+            try {
+                // TODO(b/150499490): route the intent to the client app to have it fired there,
+                //  so that it will appear as a part of the same task as the client app (similar
+                //  to the authentication flow).
+                action.sendIntent(null, 0, null, null, null);
+            } catch (IntentSender.SendIntentException e) {
+                onErrorCallback.run();
+                Slog.w(TAG, "Error sending inline action intent");
+            }
         };
         return new InlineSuggestion(inlineSuggestionInfo,
-                createInlineContentProvider(inlinePresentation, onClickAction, onErrorCallback,
+                createInlineContentProvider(presentation, onClickAction, onErrorCallback,
                         remoteRenderService, hostInputToken, displayId));
     }
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4cc6590..942d563 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,7 +99,7 @@
         "android.hardware.tv.cec-V1.0-java",
         "android.hardware.vibrator-java",
         "app-compat-annotations",
-        "framework-tethering-stubs",
+        "framework-tethering-stubs-module_libs_api",
         "ike-stubs",
     ],
 
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index a4a42bc..03ca1c6 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -85,6 +85,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
@@ -272,6 +273,46 @@
                 }
             };
 
+    public boolean onFactoryReset() {
+        // Wait for stable state if bluetooth is temporary state.
+        int state = getState();
+        if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
+                || state == BluetoothAdapter.STATE_TURNING_ON
+                || state == BluetoothAdapter.STATE_TURNING_OFF) {
+            if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) {
+                return false;
+            }
+        }
+
+        // Clear registered LE apps to force shut-off Bluetooth
+        clearBleApps();
+        state = getState();
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth == null) {
+                return false;
+            }
+            if (state == BluetoothAdapter.STATE_BLE_ON) {
+                addActiveLog(
+                        BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
+                        mContext.getPackageName(), false);
+                mBluetooth.onBrEdrDown();
+                return true;
+            } else if (state == BluetoothAdapter.STATE_ON) {
+                addActiveLog(
+                        BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
+                        mContext.getPackageName(), false);
+                mBluetooth.disable();
+                return true;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to shutdown Bluetooth", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
+        }
+        return false;
+    }
+
     public void onAirplaneModeChanged() {
         synchronized (this) {
             if (isBluetoothPersistedStateOn()) {
@@ -1670,7 +1711,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 "waitForOnOff(false, true)".
+                        //     is accomplished by
+                        //     "waitForState(Set.of(BluetoothAdapter.STATE_OFF))".
                         // (b) Wait until the STATE_OFF state is updated to
                         //     all components.
                         // (c) Wait until the Bluetooth process exits, and
@@ -1680,7 +1722,7 @@
                         // message. The delay time is backed off if Bluetooth
                         // continuously failed to turn on itself.
                         //
-                        waitForOnOff(false, true);
+                        waitForState(Set.of(BluetoothAdapter.STATE_OFF));
                         Message restartMsg =
                                 mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                         mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
@@ -1693,10 +1735,15 @@
                     }
                     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                     if (mEnable && mBluetooth != null) {
-                        waitForOnOff(true, false);
+                        waitForState(Set.of(BluetoothAdapter.STATE_ON));
                         mEnable = false;
                         handleDisable();
-                        waitForOnOff(false, false);
+                        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));
                     } else {
                         mEnable = false;
                         handleDisable();
@@ -1819,9 +1866,14 @@
                     }
 
                     if (!mEnable) {
-                        waitForOnOff(true, false);
+                        waitForState(Set.of(BluetoothAdapter.STATE_ON));
                         handleDisable();
-                        waitForOnOff(false, false);
+                        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));
                     }
                     break;
                 }
@@ -1853,7 +1905,7 @@
                             == BluetoothAdapter.STATE_OFF)) {
                         if (mEnable) {
                             Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
-                            waitForOnOff(false, true);
+                            waitForState(Set.of(BluetoothAdapter.STATE_OFF));
                             Message restartMsg =
                                     mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                             mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
@@ -1982,7 +2034,7 @@
                             mState = BluetoothAdapter.STATE_TURNING_ON;
                         }
 
-                        waitForOnOff(true, false);
+                        waitForState(Set.of(BluetoothAdapter.STATE_ON));
 
                         if (mState == BluetoothAdapter.STATE_TURNING_ON) {
                             bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
@@ -1997,7 +2049,8 @@
                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
                                 BluetoothAdapter.STATE_TURNING_OFF);
 
-                        boolean didDisableTimeout = !waitForOnOff(false, true);
+                        boolean didDisableTimeout =
+                                !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
 
                         bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
                                 BluetoothAdapter.STATE_OFF);
@@ -2243,12 +2296,7 @@
         }
     }
 
-    /**
-     *  if on is true, wait for state become ON
-     *  if off is true, wait for state become OFF
-     *  if both on and off are false, wait for state not ON
-     */
-    private boolean waitForOnOff(boolean on, boolean off) {
+    private boolean waitForState(Set<Integer> states) {
         int i = 0;
         while (i < 10) {
             try {
@@ -2256,18 +2304,8 @@
                 if (mBluetooth == null) {
                     break;
                 }
-                if (on) {
-                    if (mBluetooth.getState() == BluetoothAdapter.STATE_ON) {
-                        return true;
-                    }
-                } else if (off) {
-                    if (mBluetooth.getState() == BluetoothAdapter.STATE_OFF) {
-                        return true;
-                    }
-                } else {
-                    if (mBluetooth.getState() != BluetoothAdapter.STATE_ON) {
-                        return true;
-                    }
+                if (states.contains(mBluetooth.getState())) {
+                    return true;
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "getState()", e);
@@ -2275,14 +2313,10 @@
             } finally {
                 mBluetoothLock.readLock().unlock();
             }
-            if (on || off) {
-                SystemClock.sleep(300);
-            } else {
-                SystemClock.sleep(50);
-            }
+            SystemClock.sleep(300);
             i++;
         }
-        Slog.e(TAG, "waitForOnOff time out");
+        Slog.e(TAG, "waitForState " + states + " time out");
         return false;
     }
 
@@ -2343,7 +2377,7 @@
                 mContext.getPackageName(), false);
         handleDisable();
 
-        waitForOnOff(false, true);
+        waitForState(Set.of(BluetoothAdapter.STATE_OFF));
 
         sendBluetoothServiceDownCallback();
 
@@ -2533,6 +2567,8 @@
                 return "USER_SWITCH";
             case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:
                 return "RESTORE_USER_SETTING";
+            case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET:
+                return "FACTORY_RESET";
             case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
             default: return "UNKNOWN[" + reason + "]";
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 16dd3ad..7287a44 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -101,7 +101,6 @@
 import android.net.NetworkProvider;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkRequest;
-import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
 import android.net.NetworkStack;
 import android.net.NetworkStackClient;
@@ -274,9 +273,6 @@
     // connect anyway?" dialog after the user selects a network that doesn't validate.
     private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
 
-    // How long to dismiss network notification.
-    private static final int TIMEOUT_NOTIFICATION_DELAY_MS = 20 * 1000;
-
     // Default to 30s linger time-out. Modifiable only for testing.
     private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
     private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
@@ -524,18 +520,13 @@
     private static final int EVENT_PROVISIONING_NOTIFICATION = 43;
 
     /**
-     * This event can handle dismissing notification by given network id.
-     */
-    private static final int EVENT_TIMEOUT_NOTIFICATION = 44;
-
-    /**
      * Used to specify whether a network should be used even if connectivity is partial.
      * arg1 = whether to accept the network if its connectivity is partial (1 for true or 0 for
      * false)
      * arg2 = whether to remember this choice in the future (1 for true or 0 for false)
      * obj  = network
      */
-    private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 45;
+    private static final int EVENT_SET_ACCEPT_PARTIAL_CONNECTIVITY = 44;
 
     /**
      * Event for NetworkMonitor to inform ConnectivityService that the probe status has changed.
@@ -544,7 +535,7 @@
      * arg1 = A bitmask to describe which probes are completed.
      * arg2 = A bitmask to describe which probes are successful.
      */
-    public static final int EVENT_PROBE_STATUS_CHANGED = 46;
+    public static final int EVENT_PROBE_STATUS_CHANGED = 45;
 
     /**
      * Event for NetworkMonitor to inform ConnectivityService that captive portal data has changed.
@@ -552,7 +543,7 @@
      * arg2 = netId
      * obj = captive portal data
      */
-    private static final int EVENT_CAPPORT_DATA_CHANGED = 47;
+    private static final int EVENT_CAPPORT_DATA_CHANGED = 46;
 
     /**
      * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
@@ -2731,8 +2722,7 @@
                     break;
                 }
                 case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: {
-                    final NetworkScore ns = (NetworkScore) msg.obj;
-                    updateNetworkScore(nai, ns);
+                    updateNetworkScore(nai, msg.arg1);
                     break;
                 }
                 case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
@@ -2879,13 +2869,6 @@
             final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
             final boolean wasValidated = nai.lastValidated;
             final boolean wasDefault = isDefaultNetwork(nai);
-            // Only show a connected notification if the network is pending validation
-            // after the captive portal app was open, and it has now validated.
-            if (nai.captivePortalValidationPending && valid) {
-                // User is now logged in, network validated.
-                nai.captivePortalValidationPending = false;
-                showNetworkNotification(nai, NotificationType.LOGGED_IN);
-            }
 
             if (DBG) {
                 final String logMsg = !TextUtils.isEmpty(redirectUrl)
@@ -3766,12 +3749,6 @@
                 new CaptivePortal(new CaptivePortalImpl(network).asBinder()));
         appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
 
-        // This runs on a random binder thread, but getNetworkAgentInfoForNetwork is thread-safe,
-        // and captivePortalValidationPending is volatile.
-        final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
-        if (nai != null) {
-            nai.captivePortalValidationPending = true;
-        }
         Binder.withCleanCallingIdentity(() ->
                 mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
     }
@@ -3890,14 +3867,6 @@
         final String action;
         final boolean highPriority;
         switch (type) {
-            case LOGGED_IN:
-                action = Settings.ACTION_WIFI_SETTINGS;
-                mHandler.removeMessages(EVENT_TIMEOUT_NOTIFICATION);
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NOTIFICATION,
-                        nai.network.netId, 0), TIMEOUT_NOTIFICATION_DELAY_MS);
-                // High priority because it is a direct result of the user logging in to a portal.
-                highPriority = true;
-                break;
             case NO_INTERNET:
                 action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
                 // High priority because it is only displayed for explicitly selected networks.
@@ -3925,7 +3894,7 @@
         }
 
         Intent intent = new Intent(action);
-        if (type != NotificationType.LOGGED_IN && type != NotificationType.PRIVATE_DNS_BROKEN) {
+        if (type != NotificationType.PRIVATE_DNS_BROKEN) {
             intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             intent.setClassName("com.android.settings",
@@ -4141,9 +4110,6 @@
                 case EVENT_DATA_SAVER_CHANGED:
                     handleRestrictBackgroundChanged(toBool(msg.arg1));
                     break;
-                case EVENT_TIMEOUT_NOTIFICATION:
-                    mNotifier.clearNotification(msg.arg1, NotificationType.LOGGED_IN);
-                    break;
             }
         }
     }
@@ -5819,12 +5785,10 @@
         // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
         // satisfies mDefaultRequest.
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
-        final NetworkScore ns = new NetworkScore();
-        ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
-                ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this,
-                mNetd, mDnsResolver, mNMS, providerId);
+                currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
+                this, mNetd, mDnsResolver, mNMS, providerId);
         // Make sure the network capabilities reflect what the agent info says.
         nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
         final String extraInfo = networkInfo.getExtraInfo();
@@ -7082,9 +7046,9 @@
         }
     }
 
-    private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) {
-        if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + ns);
-        nai.setNetworkScore(ns);
+    private void updateNetworkScore(@NonNull final NetworkAgentInfo nai, final int score) {
+        if (VDBG || DDBG) log("updateNetworkScore for " + nai.toShortString() + " to " + score);
+        nai.setScore(score);
         rematchAllNetworksAndRequests();
         sendUpdatedScoreToFactories(nai);
     }
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b464422..2cfe404 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -161,6 +161,9 @@
     private final Runnable mSaveToFile = this::saveToFile;
     private final SystemClock mSystemClock;
     private final BootThreshold mBootThreshold;
+    // The set of packages that have been synced with the ExplicitHealthCheckController
+    @GuardedBy("mLock")
+    private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
     @GuardedBy("mLock")
     private boolean mIsPackagesReady;
     // Flag to control whether explicit health checks are supported or not
@@ -624,17 +627,22 @@
      * @see #syncRequestsAsync
      */
     private void syncRequests() {
-        Set<String> packages = null;
+        boolean syncRequired = false;
         synchronized (mLock) {
             if (mIsPackagesReady) {
-                packages = getPackagesPendingHealthChecksLocked();
+                Set<String> packages = getPackagesPendingHealthChecksLocked();
+                if (!packages.equals(mRequestedHealthCheckPackages)) {
+                    syncRequired = true;
+                    mRequestedHealthCheckPackages = packages;
+                }
             } // else, we will sync requests when packages become ready
         }
 
         // Call outside lock to avoid holding lock when calling into the controller.
-        if (packages != null) {
-            Slog.i(TAG, "Syncing health check requests for packages: " + packages);
-            mHealthCheckController.syncRequests(packages);
+        if (syncRequired) {
+            Slog.i(TAG, "Syncing health check requests for packages: "
+                    + mRequestedHealthCheckPackages);
+            mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
         }
     }
 
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 1415433..7dedad7 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -167,14 +167,13 @@
 
         @Override
         public String toString() {
-            return "{callingPackage=" + callingPackage + " binder=" + binder
-                    + " callback=" + callback
+            return "{callingPackage=" + pii(callingPackage) + " callerUid=" + callerUid + " binder="
+                    + binder + " callback=" + callback
                     + " onSubscriptionsChangedListenererCallback="
                     + onSubscriptionsChangedListenerCallback
                     + " onOpportunisticSubscriptionsChangedListenererCallback="
-                    + onOpportunisticSubscriptionsChangedListenerCallback
-                    + " callerUid=" + callerUid + " subId=" + subId + " phoneId=" + phoneId
-                    + " events=" + Integer.toHexString(events) + "}";
+                    + onOpportunisticSubscriptionsChangedListenerCallback + " subId=" + subId
+                    + " phoneId=" + phoneId + " events=" + Integer.toHexString(events) + "}";
         }
     }
 
@@ -598,9 +597,9 @@
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
-            log("listen oscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
-                + " callerUserId="  + callerUserId + " callback=" + callback
-                + " callback.asBinder=" + callback.asBinder());
+            log("listen oscl: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+                    + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId
+                    + " callback=" + callback + " callback.asBinder=" + callback.asBinder());
         }
 
         synchronized (mRecords) {
@@ -652,9 +651,9 @@
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
         if (VDBG) {
-            log("listen ooscl: E pkg=" + callingPackage + " myUserId=" + UserHandle.myUserId()
-                    + " callerUserId="  + callerUserId + " callback=" + callback
-                    + " callback.asBinder=" + callback.asBinder());
+            log("listen ooscl: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+                    + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId
+                    + " callback=" + callback + " callback.asBinder=" + callback.asBinder());
         }
 
         synchronized (mRecords) {
@@ -769,9 +768,9 @@
             IPhoneStateListener callback, int events, boolean notifyNow, int subId) {
         int callerUserId = UserHandle.getCallingUserId();
         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
-        String str = "listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
-                + " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
-                + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+        String str = "listen: E pkg=" + pii(callingPackage) + " uid=" + Binder.getCallingUid()
+                + " events=0x" + Integer.toHexString(events) + " notifyNow=" + notifyNow + " subId="
+                + subId + " myUserId=" + UserHandle.myUserId() + " callerUserId=" + callerUserId;
         mListenLog.log(str);
         if (VDBG) {
             log(str);
@@ -2957,4 +2956,14 @@
         if (info == null) return INVALID_SIM_SLOT_INDEX;
         return info.getSimSlotIndex();
     }
+
+    /**
+     * On certain build types, we should redact information by default. UID information will be
+     * preserved in the same log line, so no debugging capability is lost in full bug reports.
+     * However, privacy-constrained bug report types (e.g. connectivity) cannot display raw
+     * package names on user builds as it's considered an information leak.
+     */
+    private static String pii(String packageName) {
+        return Build.IS_DEBUGGABLE ? packageName : "***";
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9058ac4..f64272b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4766,7 +4766,8 @@
                 packageName == null ? ApplicationExitInfo.REASON_USER_STOPPED
                         : ApplicationExitInfo.REASON_USER_REQUESTED,
                 ApplicationExitInfo.SUBREASON_UNKNOWN,
-                packageName == null ? ("stop user " + userId) : ("stop " + packageName));
+                (packageName == null ? ("stop user " + userId) : ("stop " + packageName))
+                + " due to " + reason);
 
         didSomething |=
                 mAtmInternal.onForceStopPackage(packageName, doit, evenPersistent, userId);
@@ -17066,6 +17067,7 @@
             proc.lastCachedPss = pss;
             proc.lastCachedSwapPss = swapPss;
         }
+        proc.mLastRss = rss;
 
         final SparseArray<Pair<Long, String>> watchUids
                 = mMemWatchProcesses.getMap().get(proc.processName);
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index a09aa64..028a059 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -129,7 +129,7 @@
     private final ProcessMap<AppExitInfoContainer> mData;
 
     /** A pool of raw {@link android.app.ApplicationExitInfo} records. */
-    @GuardedBy("mService")
+    @GuardedBy("mLock")
     private final SynchronizedPool<ApplicationExitInfo> mRawRecordsPool;
 
     /**
@@ -204,8 +204,7 @@
         });
     }
 
-    @GuardedBy("mService")
-    void scheduleNoteProcessDiedLocked(final ProcessRecord app) {
+    void scheduleNoteProcessDied(final ProcessRecord app) {
         if (app == null || app.info == null) {
             return;
         }
@@ -214,11 +213,9 @@
             if (!mAppExitInfoLoaded) {
                 return;
             }
+            mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecordLocked(app))
+                    .sendToTarget();
         }
-        // The current thread is holding the global lock, let's extract the info from it
-        // and schedule the info note task in the kill handler.
-        mKillHandler.obtainMessage(KillHandler.MSG_PROC_DIED, obtainRawRecordLocked(app))
-                .sendToTarget();
     }
 
     void scheduleNoteAppKill(final ProcessRecord app, final @Reason int reason,
@@ -227,8 +224,6 @@
             if (!mAppExitInfoLoaded) {
                 return;
             }
-        }
-        synchronized (mService) {
             if (app == null || app.info == null) {
                 return;
             }
@@ -247,8 +242,6 @@
             if (!mAppExitInfoLoaded) {
                 return;
             }
-        }
-        synchronized (mService) {
             ProcessRecord app;
             synchronized (mService.mPidsSelfLocked) {
                 app = mService.mPidsSelfLocked.get(pid);
@@ -512,9 +505,13 @@
     @VisibleForTesting
     void onPackageRemoved(String packageName, int uid, boolean allUsers) {
         if (packageName != null) {
-            mAppExitInfoSourceZygote.removeByUid(uid, allUsers);
-            mAppExitInfoSourceLmkd.removeByUid(uid, allUsers);
-            mIsolatedUidRecords.removeAppUid(uid, allUsers);
+            final boolean removeUid = TextUtils.isEmpty(
+                    mService.mPackageManagerInt.getNameForUid(uid));
+            if (removeUid) {
+                mAppExitInfoSourceZygote.removeByUid(uid, allUsers);
+                mAppExitInfoSourceLmkd.removeByUid(uid, allUsers);
+                mIsolatedUidRecords.removeAppUid(uid, allUsers);
+            }
             removePackage(packageName, allUsers ? UserHandle.USER_ALL : UserHandle.getUserId(uid));
             schedulePersistProcessExitInfo(true);
         }
@@ -540,6 +537,11 @@
         mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
+                boolean replacing = intent.getBooleanExtra(
+                        Intent.EXTRA_REPLACING, false);
+                if (replacing) {
+                    return;
+                }
                 int uid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
                 boolean allUsers = intent.getBooleanExtra(
                         Intent.EXTRA_REMOVED_FOR_ALL_USERS, false);
@@ -823,7 +825,7 @@
     }
 
     @VisibleForTesting
-    @GuardedBy("mService")
+    @GuardedBy("mLock")
     ApplicationExitInfo obtainRawRecordLocked(ProcessRecord app) {
         ApplicationExitInfo info = mRawRecordsPool.acquire();
         if (info == null) {
@@ -842,15 +844,15 @@
         info.setReason(ApplicationExitInfo.REASON_UNKNOWN);
         info.setStatus(0);
         info.setImportance(procStateToImportance(app.setProcState));
-        info.setPss(app.lastMemInfo == null ? 0 : app.lastMemInfo.getTotalPss());
-        info.setRss(app.lastMemInfo == null ? 0 : app.lastMemInfo.getTotalRss());
+        info.setPss(app.lastPss);
+        info.setRss(app.mLastRss);
         info.setTimestamp(System.currentTimeMillis());
 
         return info;
     }
 
     @VisibleForTesting
-    @GuardedBy("mService")
+    @GuardedBy("mLock")
     void recycleRawRecordLocked(ApplicationExitInfo info) {
         info.setProcessName(null);
         info.setDescription(null);
@@ -1135,8 +1137,6 @@
                     ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
                     synchronized (mLock) {
                         handleNoteProcessDiedLocked(raw);
-                    }
-                    synchronized (mService) {
                         recycleRawRecordLocked(raw);
                     }
                 }
@@ -1145,8 +1145,6 @@
                     ApplicationExitInfo raw = (ApplicationExitInfo) msg.obj;
                     synchronized (mLock) {
                         handleNoteAppKillLocked(raw);
-                    }
-                    synchronized (mService) {
                         recycleRawRecordLocked(raw);
                     }
                 }
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 3a6065e..86d9028 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -121,6 +121,7 @@
     static final int COMPACT_PROCESS_MSG = 1;
     static final int COMPACT_SYSTEM_MSG = 2;
     static final int SET_FROZEN_PROCESS_MSG = 3;
+    static final int REPORT_UNFREEZE_MSG = 4;
 
     //TODO:change this static definition into a configurable flag.
     static final int FREEZE_TIMEOUT_MS = 500;
@@ -613,30 +614,6 @@
                 FREEZE_TIMEOUT_MS);
     }
 
-    private final class UnfreezeStats {
-        final int mPid;
-        final String mName;
-        final long mFrozenDuration;
-
-        UnfreezeStats(int pid, String name, long frozenDuration) {
-            mPid = pid;
-            mName = name;
-            mFrozenDuration = frozenDuration;
-        }
-
-        public int getPid() {
-            return mPid;
-        }
-
-        public String getName() {
-            return mName;
-        }
-
-        public long getFrozenDuration() {
-            return mFrozenDuration;
-        }
-    }
-
     @GuardedBy("mAm")
     void unfreezeAppLocked(ProcessRecord app) {
         mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
@@ -667,12 +644,11 @@
                 Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
             }
 
-            UnfreezeStats stats = new UnfreezeStats(app.pid, app.processName,
-                    app.freezeUnfreezeTime - freezeTime);
-
             mFreezeHandler.sendMessage(
-                    mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, REPORT_UNFREEZE, 0,
-                        stats));
+                    mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
+                        app.pid,
+                        (int) Math.min(app.freezeUnfreezeTime - freezeTime, Integer.MAX_VALUE),
+                        app.processName));
         }
     }
 
@@ -945,14 +921,19 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what != SET_FROZEN_PROCESS_MSG) {
-                return;
-            }
+            switch (msg.what) {
+                case SET_FROZEN_PROCESS_MSG:
+                    freezeProcess((ProcessRecord) msg.obj);
+                    break;
+                case REPORT_UNFREEZE_MSG:
+                    int pid = msg.arg1;
+                    int frozenDuration = msg.arg2;
+                    String processName = (String) msg.obj;
 
-            if (msg.arg1 == DO_FREEZE) {
-                freezeProcess((ProcessRecord) msg.obj);
-            } else if (msg.arg1 == REPORT_UNFREEZE) {
-                reportUnfreeze((UnfreezeStats) msg.obj);
+                    reportUnfreeze(pid, frozenDuration, processName);
+                    break;
+                default:
+                    return;
             }
         }
 
@@ -1015,18 +996,18 @@
             }
         }
 
-        private void reportUnfreeze(UnfreezeStats stats) {
+        private void reportUnfreeze(int pid, int frozenDuration, String processName) {
 
-            EventLog.writeEvent(EventLogTags.AM_UNFREEZE, stats.getPid(), stats.getName());
+            EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName);
 
             // See above for why we're not taking mPhenotypeFlagLock here
             if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
                 FrameworkStatsLog.write(
                         FrameworkStatsLog.APP_FREEZE_CHANGED,
                         FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
-                        stats.getPid(),
-                        stats.getName(),
-                        stats.getFrozenDuration());
+                        pid,
+                        processName,
+                        frozenDuration);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 7cc2e8e..1f826b5 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -16,12 +16,6 @@
 
 # Windows & Activities
 ogunwale@google.com
-jjaggi@google.com
-racarr@google.com
-chaviw@google.com
-vishnun@google.com
-akulian@google.com
-roosa@google.com
 
 # Permissions & Packages
 svetoslavganov@google.com
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 644f0f7..b584ea5 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1708,11 +1708,6 @@
                                     // TOP process passes all capabilities to the service.
                                     capability |= PROCESS_CAPABILITY_ALL;
                                 }
-                            } else if (clientProcState
-                                    <= PROCESS_STATE_FOREGROUND_SERVICE) {
-                                if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
-                                    clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
-                                }
                             }
                         } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
                             if (clientProcState <
@@ -2036,7 +2031,7 @@
             case PROCESS_STATE_TOP:
                 return PROCESS_CAPABILITY_ALL;
             case PROCESS_STATE_BOUND_TOP:
-                return PROCESS_CAPABILITY_ALL_IMPLICIT;
+                return PROCESS_CAPABILITY_NONE;
             case PROCESS_STATE_FOREGROUND_SERVICE:
                 if (app.hasForegroundServices()) {
                     // Capability from FGS are conditional depending on foreground service type in
@@ -2044,10 +2039,12 @@
                     return PROCESS_CAPABILITY_NONE;
                 } else {
                     // process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
+                    // the implicit capability could be removed in the future, client should use
+                    // BIND_INCLUDE_CAPABILITY flag.
                     return PROCESS_CAPABILITY_ALL_IMPLICIT;
                 }
             case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
-                return PROCESS_CAPABILITY_ALL_IMPLICIT;
+                return PROCESS_CAPABILITY_NONE;
             default:
                 return PROCESS_CAPABILITY_NONE;
         }
@@ -2588,8 +2585,13 @@
             return;
         }
 
+        // if an app is already frozen and shouldNotFreeze becomes true, immediately unfreeze
+        if (app.frozen && app.shouldNotFreeze) {
+            mCachedAppOptimizer.unfreezeAppLocked(app);
+        }
+
         // Use current adjustment when freezing, set adjustment when unfreezing.
-        if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen) {
+        if (app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ && !app.frozen && !app.shouldNotFreeze) {
             mCachedAppOptimizer.freezeAppAsync(app);
         } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ && app.frozen) {
             mCachedAppOptimizer.unfreezeAppLocked(app);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index a9d18e0..6b16513 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3773,7 +3773,7 @@
         }
 
         Watchdog.getInstance().processDied(app.processName, app.pid);
-        mAppExitInfoTracker.scheduleNoteProcessDiedLocked(app);
+        mAppExitInfoTracker.scheduleNoteProcessDied(app);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index f2ca1da..c029811 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -323,6 +323,8 @@
     // set of disabled compat changes for the process (all others are enabled)
     long[] mDisabledCompatChanges;
 
+    long mLastRss;               // Last computed memory rss.
+
     // The precede instance of the process, which would exist when the previous process is killed
     // but not fully dead yet; in this case, the new instance of the process should be held until
     // this precede instance is fully dead.
@@ -431,6 +433,7 @@
                 pw.print(" lastSwapPss="); DebugUtils.printSizeValue(pw, lastSwapPss*1024);
                 pw.print(" lastCachedPss="); DebugUtils.printSizeValue(pw, lastCachedPss*1024);
                 pw.print(" lastCachedSwapPss="); DebugUtils.printSizeValue(pw, lastCachedSwapPss*1024);
+        pw.print(" lastRss="); DebugUtils.printSizeValue(pw, mLastRss * 1024);
                 pw.println();
         pw.print(prefix); pw.print("procStateMemTracker: ");
         procStateMemTracker.dumpLine(pw);
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index bfc2f82..61bede9 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -219,6 +219,19 @@
     }
 
     /**
+     * Returns whether the change is marked as disabled.
+     */
+    boolean isDisabled(long changeId) {
+        synchronized (mChanges) {
+            CompatChange c = mChanges.get(changeId);
+            if (c == null) {
+                return false;
+            }
+            return c.getDisabled();
+        }
+    }
+
+    /**
      * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
      * restores the default behaviour for the given change and app, once any app processes have been
      * restarted.
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index 9e18c74..f5d6e5a 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -59,6 +59,7 @@
         boolean debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild();
         boolean finalBuild = mAndroidBuildClassifier.isFinalBuild();
         int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId);
+        boolean disabled = mCompatConfig.isDisabled(changeId);
 
         // Allow any override for userdebug or eng builds.
         if (debuggableBuild) {
@@ -83,12 +84,12 @@
         if (!finalBuild) {
             return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
         }
-        // Do not allow overriding non-target sdk gated changes on user builds
-        if (minTargetSdk == -1) {
+        // Do not allow overriding default enabled changes on user builds
+        if (minTargetSdk == -1 && !disabled) {
             return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk);
         }
         // Only allow to opt-in for a targetSdk gated change.
-        if (applicationInfo.targetSdkVersion < minTargetSdk) {
+        if (disabled || applicationInfo.targetSdkVersion < minTargetSdk) {
             return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk);
         }
         return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 58b5cba..2f04715 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -32,7 +32,6 @@
 import android.net.NetworkInfo;
 import android.net.NetworkMonitorManager;
 import android.net.NetworkRequest;
-import android.net.NetworkScore;
 import android.net.NetworkState;
 import android.os.Handler;
 import android.os.INetworkManagementService;
@@ -161,10 +160,6 @@
     // Whether a captive portal was found during the last network validation attempt.
     public boolean lastCaptivePortalDetected;
 
-    // Indicates the captive portal app was opened to show a login UI to the user, but the network
-    // has not validated yet.
-    public volatile boolean captivePortalValidationPending;
-
     // Set to true when partial connectivity was detected.
     public boolean partialConnectivity;
 
@@ -236,10 +231,8 @@
     // validated).
     private boolean mLingering;
 
-    // This represents the characteristics of a network that affects how good the network is
-    // considered for a particular use.
-    @NonNull
-    private NetworkScore mNetworkScore;
+    // This represents the quality of the network with no clear scale.
+    private int mScore;
 
     // The list of NetworkRequests being satisfied by this Network.
     private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -268,7 +261,7 @@
     private final Handler mHandler;
 
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
-            LinkProperties lp, NetworkCapabilities nc, @NonNull NetworkScore ns, Context context,
+            LinkProperties lp, NetworkCapabilities nc, int score, Context context,
             Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
             IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
         this.messenger = messenger;
@@ -277,7 +270,7 @@
         networkInfo = info;
         linkProperties = lp;
         networkCapabilities = nc;
-        mNetworkScore = ns;
+        mScore = score;
         clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
         mConnService = connService;
         mContext = context;
@@ -491,7 +484,7 @@
             return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
         }
 
-        int score = mNetworkScore.getIntExtension(NetworkScore.LEGACY_SCORE);
+        int score = mScore;
         if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
             score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
         }
@@ -520,13 +513,8 @@
         return getCurrentScore(true);
     }
 
-    public void setNetworkScore(@NonNull NetworkScore ns) {
-        mNetworkScore = ns;
-    }
-
-    @NonNull
-    public NetworkScore getNetworkScore() {
-        return mNetworkScore;
+    public void setScore(final int score) {
+        mScore = score;
     }
 
     public NetworkState getNetworkState() {
@@ -646,7 +634,6 @@
                 + "acceptUnvalidated{" + networkAgentConfig.acceptUnvalidated + "} "
                 + "everCaptivePortalDetected{" + everCaptivePortalDetected + "} "
                 + "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} "
-                + "captivePortalValidationPending{" + captivePortalValidationPending + "} "
                 + "partialConnectivity{" + partialConnectivity + "} "
                 + "acceptPartialConnectivity{" + networkAgentConfig.acceptPartialConnectivity + "} "
                 + "clat{" + clatd + "} "
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 25c761a..0925de8 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -51,7 +51,6 @@
         LOST_INTERNET(SystemMessage.NOTE_NETWORK_LOST_INTERNET),
         NETWORK_SWITCH(SystemMessage.NOTE_NETWORK_SWITCH),
         NO_INTERNET(SystemMessage.NOTE_NETWORK_NO_INTERNET),
-        LOGGED_IN(SystemMessage.NOTE_NETWORK_LOGGED_IN),
         PARTIAL_CONNECTIVITY(SystemMessage.NOTE_NETWORK_PARTIAL_CONNECTIVITY),
         SIGN_IN(SystemMessage.NOTE_NETWORK_SIGN_IN),
         PRIVATE_DNS_BROKEN(SystemMessage.NOTE_NETWORK_PRIVATE_DNS_BROKEN);
@@ -114,14 +113,10 @@
         }
     }
 
-    private static int getIcon(int transportType, NotificationType notifyType) {
-        if (transportType != TRANSPORT_WIFI) {
-            return R.drawable.stat_notify_rssi_in_range;
-        }
-
-        return notifyType == NotificationType.LOGGED_IN
-            ? R.drawable.ic_wifi_signal_4
-            : R.drawable.stat_notify_wifi_in_range;  // TODO: Distinguish ! from ?.
+    private static int getIcon(int transportType) {
+        return (transportType == TRANSPORT_WIFI)
+                ? R.drawable.stat_notify_wifi_in_range :  // TODO: Distinguish ! from ?.
+                R.drawable.stat_notify_rssi_in_range;
     }
 
     /**
@@ -185,7 +180,7 @@
         Resources r = mContext.getResources();
         final CharSequence title;
         final CharSequence details;
-        int icon = getIcon(transportType, notifyType);
+        int icon = getIcon(transportType);
         if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
             title = r.getString(R.string.wifi_no_internet,
                     WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID()));
@@ -235,9 +230,6 @@
                     details = r.getString(R.string.network_available_sign_in_detailed, name);
                     break;
             }
-        } else if (notifyType == NotificationType.LOGGED_IN) {
-            title = WifiInfo.sanitizeSsid(nai.networkCapabilities.getSSID());
-            details = r.getString(R.string.captive_portal_logged_in_detailed);
         } else if (notifyType == NotificationType.NETWORK_SWITCH) {
             String fromTransport = getTransportName(transportType);
             String toTransport = getTransportName(approximateTransportType(switchToNai));
@@ -379,7 +371,6 @@
             case NETWORK_SWITCH:
                 return 2;
             case LOST_INTERNET:
-            case LOGGED_IN:
                 return 1;
             default:
                 return 0;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 968528c..7c3cab1 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -951,18 +951,18 @@
                 || isVpnServicePreConsented(context, packageName);
     }
 
-    private int getAppUid(String app, int userHandle) {
+    private int getAppUid(final String app, final int userHandle) {
         if (VpnConfig.LEGACY_VPN.equals(app)) {
             return Process.myUid();
         }
         PackageManager pm = mContext.getPackageManager();
-        int result;
-        try {
-            result = pm.getPackageUidAsUser(app, userHandle);
-        } catch (NameNotFoundException e) {
-            result = -1;
-        }
-        return result;
+        return Binder.withCleanCallingIdentity(() -> {
+            try {
+                return pm.getPackageUidAsUser(app, userHandle);
+            } catch (NameNotFoundException e) {
+                return -1;
+            }
+        });
     }
 
     private boolean doesPackageTargetAtLeastQ(String packageName) {
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index f773825..6da0de1 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -52,7 +52,6 @@
 import android.os.HandlerThread;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.security.FileIntegrityManager;
 import android.util.Slog;
 import android.util.apk.SourceStampVerificationResult;
 import android.util.apk.SourceStampVerifier;
@@ -122,7 +121,6 @@
     private final PackageManagerInternal mPackageManagerInternal;
     private final RuleEvaluationEngine mEvaluationEngine;
     private final IntegrityFileManager mIntegrityFileManager;
-    private final FileIntegrityManager mFileIntegrityManager;
 
     /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
     public static AppIntegrityManagerServiceImpl create(Context context) {
@@ -134,7 +132,6 @@
                 LocalServices.getService(PackageManagerInternal.class),
                 RuleEvaluationEngine.getRuleEvaluationEngine(),
                 IntegrityFileManager.getInstance(),
-                (FileIntegrityManager) context.getSystemService(Context.FILE_INTEGRITY_SERVICE),
                 handlerThread.getThreadHandler());
     }
 
@@ -144,13 +141,11 @@
             PackageManagerInternal packageManagerInternal,
             RuleEvaluationEngine evaluationEngine,
             IntegrityFileManager integrityFileManager,
-            FileIntegrityManager fileIntegrityManager,
             Handler handler) {
         mContext = context;
         mPackageManagerInternal = packageManagerInternal;
         mEvaluationEngine = evaluationEngine;
         mIntegrityFileManager = integrityFileManager;
-        mFileIntegrityManager = fileIntegrityManager;
         mHandler = handler;
 
         IntentFilter integrityVerificationFilter = new IntentFilter();
@@ -476,6 +471,8 @@
                 SourceStampVerifier.verify(installationPath.getAbsolutePath());
         appInstallMetadata.setIsStampPresent(sourceStampVerificationResult.isPresent());
         appInstallMetadata.setIsStampVerified(sourceStampVerificationResult.isVerified());
+        // A verified stamp is set to be trusted.
+        appInstallMetadata.setIsStampTrusted(sourceStampVerificationResult.isVerified());
         if (sourceStampVerificationResult.isVerified()) {
             X509Certificate sourceStampCertificate =
                     (X509Certificate) sourceStampVerificationResult.getCertificate();
@@ -488,16 +485,6 @@
                 throw new IllegalArgumentException(
                         "Error computing source stamp certificate digest", e);
             }
-            // Checks if the source stamp certificate is trusted.
-            try {
-                appInstallMetadata.setIsStampTrusted(
-                        mFileIntegrityManager.isApkVeritySupported()
-                                && mFileIntegrityManager.isAppSourceCertificateTrusted(
-                                        sourceStampCertificate));
-            } catch (CertificateEncodingException e) {
-                throw new IllegalArgumentException(
-                        "Error checking if source stamp certificate is trusted", e);
-            }
         }
     }
 
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index b456737..2aa53cc 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -60,6 +60,8 @@
     private Connection mActiveConnection;
     private boolean mConnectionReady;
 
+    private RouteDiscoveryPreference mPendingDiscoveryPreference = null;
+
     MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
             int userId) {
         super(componentName);
@@ -99,6 +101,8 @@
         if (mConnectionReady) {
             mActiveConnection.updateDiscoveryPreference(discoveryPreference);
             updateBinding();
+        } else {
+            mPendingDiscoveryPreference = discoveryPreference;
         }
     }
 
@@ -271,6 +275,10 @@
     private void onConnectionReady(Connection connection) {
         if (mActiveConnection == connection) {
             mConnectionReady = true;
+            if (mPendingDiscoveryPreference != null) {
+                updateDiscoveryPreference(mPendingDiscoveryPreference);
+                mPendingDiscoveryPreference = null;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ee5a4fe..4af31b0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -306,9 +306,8 @@
     /** Data layer operation counters for splicing into other structures. */
     private NetworkStats mUidOperations = new NetworkStats(0L, 10);
 
-    /** Must be set in factory by calling #setHandler. */
-    private Handler mHandler;
-    private Handler.Callback mHandlerCallback;
+    @NonNull
+    private final Handler mHandler;
 
     private volatile boolean mSystemReady;
     private long mPersistThreshold = 2 * MB_IN_BYTES;
@@ -324,6 +323,9 @@
 
     private final static int DUMP_STATS_SESSION_COUNT = 20;
 
+    @NonNull
+    private final Dependencies mDeps;
+
     private static @NonNull File getDefaultSystemDir() {
         return new File(Environment.getDataDirectory(), "system");
     }
@@ -339,9 +341,24 @@
                 Clock.systemUTC());
     }
 
-    private static final class NetworkStatsHandler extends Handler {
-        NetworkStatsHandler(Looper looper, Handler.Callback callback) {
-            super(looper, callback);
+    private final class NetworkStatsHandler extends Handler {
+        NetworkStatsHandler(@NonNull Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_PERFORM_POLL: {
+                    performPoll(FLAG_PERSIST_ALL);
+                    break;
+                }
+                case MSG_PERFORM_POLL_REGISTER_ALERT: {
+                    performPoll(FLAG_PERSIST_NETWORK);
+                    registerGlobalAlert();
+                    break;
+                }
+            }
         }
     }
 
@@ -355,14 +372,10 @@
         NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
                 wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class),
                 new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
-                new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir());
+                new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
+                new Dependencies());
         service.registerLocalService();
 
-        HandlerThread handlerThread = new HandlerThread(TAG);
-        Handler.Callback callback = new HandlerCallback(service);
-        handlerThread.start();
-        Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback);
-        service.setHandler(handler, callback);
         return service;
     }
 
@@ -373,7 +386,7 @@
             AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
             TelephonyManager teleManager, NetworkStatsSettings settings,
             NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
-            File baseDir) {
+            File baseDir, @NonNull Dependencies deps) {
         mContext = Objects.requireNonNull(context, "missing Context");
         mNetworkManager = Objects.requireNonNull(networkManager,
             "missing INetworkManagementService");
@@ -387,6 +400,26 @@
         mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
         mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
         mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
+        mDeps = Objects.requireNonNull(deps, "missing Dependencies");
+
+        final HandlerThread handlerThread = mDeps.makeHandlerThread();
+        handlerThread.start();
+        mHandler = new NetworkStatsHandler(handlerThread.getLooper());
+    }
+
+    /**
+     * Dependencies of NetworkStatsService, for injection in tests.
+     */
+    // TODO: Move more stuff into dependencies object.
+    @VisibleForTesting
+    public static class Dependencies {
+        /**
+         * Create a HandlerThread to use in NetworkStatsService.
+         */
+        @NonNull
+        public HandlerThread makeHandlerThread() {
+            return new HandlerThread(TAG);
+        }
     }
 
     private void registerLocalService() {
@@ -394,12 +427,6 @@
                 new NetworkStatsManagerInternalImpl());
     }
 
-    @VisibleForTesting
-    void setHandler(Handler handler, Handler.Callback callback) {
-        mHandler = handler;
-        mHandlerCallback = callback;
-    }
-
     public void systemReady() {
         synchronized (mStatsLock) {
             mSystemReady = true;
@@ -1920,33 +1947,6 @@
 
     }
 
-    @VisibleForTesting
-    static class HandlerCallback implements Handler.Callback {
-        private final NetworkStatsService mService;
-
-        HandlerCallback(NetworkStatsService service) {
-            this.mService = service;
-        }
-
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_PERFORM_POLL: {
-                    mService.performPoll(FLAG_PERSIST_ALL);
-                    return true;
-                }
-                case MSG_PERFORM_POLL_REGISTER_ALERT: {
-                    mService.performPoll(FLAG_PERSIST_NETWORK);
-                    mService.registerGlobalAlert();
-                    return true;
-                }
-                default: {
-                    return false;
-                }
-            }
-        }
-    }
-
     private void assertSystemReady() {
         if (!mSystemReady) {
             throw new IllegalStateException("System not ready");
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index b90681d..79a4da2 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -388,7 +388,7 @@
         for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
             IntentFilter intentFilter = intents.get(i);
             if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
-                    intent.getData(), intent.getCategories(), "AppsFilter") > 0) {
+                    intent.getData(), intent.getCategories(), "AppsFilter", true) > 0) {
                 return true;
             }
         }
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index ad20d38..8eb773a 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -116,9 +116,6 @@
                 return null;
             }
 
-            // TODO(b/136132412): better way to enable privileged data loaders in tests
-            boolean checkLoader =
-                    android.os.SystemProperties.getBoolean("incremental.check_loader", false);
             int numServices = services.size();
             for (int i = 0; i < numServices; i++) {
                 ResolveInfo ri = services.get(i);
@@ -128,7 +125,7 @@
                 // If there's more than one, return the first one found.
                 try {
                     ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
-                    if (checkLoader && !ai.isPrivilegedApp()) {
+                    if (!ai.isPrivilegedApp()) {
                         Slog.w(TAG,
                                 "Data loader: " + resolved + " is not a privileged app, skipping.");
                         continue;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2d16854..62541ab 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5450,7 +5450,7 @@
                         packagePermissions, sharedUserPermissions);
             }
 
-            mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
+            mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
         }
 
         @NonNull
@@ -5504,12 +5504,12 @@
         }
 
         public void deleteUserRuntimePermissionsFile(int userId) {
-            mPersistence.deleteAsUser(UserHandle.of(userId));
+            mPersistence.deleteForUser(UserHandle.of(userId));
         }
 
         @GuardedBy("Settings.this.mLock")
         public void readStateForUserSyncLPr(int userId) {
-            RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of(
+            RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
                     userId));
             if (runtimePermissions == null) {
                 readLegacyStateForUserSyncLPr(userId);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 7dd2e55..83fe556 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -331,7 +331,8 @@
     }
 
     // Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
-    private void abortCheckpoint() {
+    private void abortCheckpoint(String errorMsg) {
+        Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
         try {
             if (supportsCheckpoint() && needsCheckpoint()) {
                 mApexManager.revertActiveSessions();
@@ -504,6 +505,8 @@
             // mode. If not, we fail all sessions.
             if (supportsCheckpoint() && !needsCheckpoint()) {
                 // TODO(b/146343545): Persist failure reason across checkpoint reboot
+                Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
+                        + " as failed.");
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
                         "Reverting back to safe state");
                 return;
@@ -524,26 +527,29 @@
 
         if (hasApex) {
             if (apexSessionInfo == null) {
+                String errorMsg = "apexd did not know anything about a staged session supposed to"
+                        + " be activated";
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        "apexd did not know anything about a staged session supposed to be"
-                        + "activated");
-                abortCheckpoint();
+                        errorMsg);
+                abortCheckpoint(errorMsg);
                 return;
             }
             if (isApexSessionFailed(apexSessionInfo)) {
+                String errorMsg = "APEX activation failed. Check logcat messages from apexd for "
+                        + "more information.";
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        "APEX activation failed. Check logcat messages from apexd for "
-                                + "more information.");
-                abortCheckpoint();
+                        errorMsg);
+                abortCheckpoint(errorMsg);
                 return;
             }
             if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
                 // Apexd did not apply the session for some unknown reason. There is no guarantee
                 // that apexd will install it next time. Safer to proactively mark as failed.
+                String errorMsg = "Staged session " + session.sessionId + "at boot didn't "
+                        + "activate nor fail. Marking it as failed anyway.";
                 session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
-                        "Staged session " + session.sessionId + "at boot didn't "
-                                + "activate nor fail. Marking it as failed anyway.");
-                abortCheckpoint();
+                        errorMsg);
+                abortCheckpoint(errorMsg);
                 return;
             }
             snapshotAndRestoreForApexSession(session);
@@ -556,7 +562,7 @@
             installApksInSession(session);
         } catch (PackageManagerException e) {
             session.setStagedSessionFailed(e.error, e.getMessage());
-            abortCheckpoint();
+            abortCheckpoint(e.getMessage());
 
             // If checkpoint is not supported, we have to handle failure for one staged session.
             if (!hasApex) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 97ce6bd..b33dc8f 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -364,12 +364,12 @@
                     (Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
         }
 
-        mPersistence.writeAsUser(roles, UserHandle.of(mUserId));
+        mPersistence.writeForUser(roles, UserHandle.of(mUserId));
     }
 
     private void readFile() {
         synchronized (mLock) {
-            RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId));
+            RolesState roles = mPersistence.readForUser(UserHandle.of(mUserId));
             if (roles == null) {
                 readLegacyFileLocked();
                 scheduleWriteFileLocked();
@@ -545,7 +545,7 @@
                 throw new IllegalStateException("This RoleUserState has already been destroyed");
             }
             mWriteHandler.removeCallbacksAndMessages(null);
-            mPersistence.deleteAsUser(UserHandle.of(mUserId));
+            mPersistence.deleteForUser(UserHandle.of(mUserId));
             mDestroyed = true;
         }
     }
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 32cff3b..98579af 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -24,6 +24,8 @@
 import static android.os.Process.getUidForPid;
 import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
 import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
+import static android.util.MathUtils.abs;
+import static android.util.MathUtils.constrain;
 
 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
 import static com.android.server.stats.pull.IonMemoryUtil.readProcessSystemIonHeapSizesFromDebugfs;
@@ -146,12 +148,15 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.MissingResourceException;
+import java.util.Random;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
@@ -169,6 +174,9 @@
     private static final String TAG = "StatsPullAtomService";
     private static final boolean DEBUG = true;
 
+    // Random seed stable for StatsPullAtomService life cycle - can be used for stable sampling
+    private static final int RANDOM_SEED = new Random().nextInt();
+
     /**
      * Lowest available uid for apps.
      *
@@ -256,6 +264,8 @@
 
     private StatsPullAtomCallbackImpl mStatsCallbackImpl;
 
+    private int mAppOpsSamplingRate = 0;
+
     public StatsPullAtomService(Context context) {
         super(context);
         mContext = context;
@@ -2877,44 +2887,7 @@
 
             HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                     TimeUnit.MILLISECONDS);
-
-            for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
-                final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
-                final int uid = uidOps.getUid();
-                for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
-                    final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
-                    for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
-                        final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);
-
-                        StatsEvent.Builder e = StatsEvent.newBuilder();
-                        e.setAtomId(atomTag);
-                        e.writeInt(uid);
-                        e.writeString(packageOps.getPackageName());
-                        e.writeInt(op.getOpCode());
-                        e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
-                        e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
-                        e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
-                        e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
-                        e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
-                        e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
-
-                        String perm = AppOpsManager.opToPermission(op.getOpCode());
-                        if (perm == null) {
-                            e.writeBoolean(false);
-                        } else {
-                            PermissionInfo permInfo;
-                            try {
-                                permInfo = mContext.getPackageManager().getPermissionInfo(perm, 0);
-                                e.writeBoolean(permInfo.getProtection() == PROTECTION_DANGEROUS);
-                            } catch (PackageManager.NameNotFoundException exception) {
-                                e.writeBoolean(false);
-                            }
-                        }
-
-                        pulledData.add(e.build());
-                    }
-                }
-            }
+            processHistoricalOps(histOps, atomTag, pulledData);
         } catch (Throwable t) {
             // TODO: catch exceptions at a more granular level
             Slog.e(TAG, "Could not read appops", t);
@@ -2945,54 +2918,12 @@
                     new HistoricalOpsRequest.Builder(0, Long.MAX_VALUE).setFlags(
                             OP_FLAGS_PULLED).build();
             appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
-
             HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
                     TimeUnit.MILLISECONDS);
-
-            for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
-                final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
-                final int uid = uidOps.getUid();
-                for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
-                    final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
-                    for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
-                            featureIdx++) {
-                        final AppOpsManager.HistoricalFeatureOps featureOps =
-                                packageOps.getFeatureOpsAt(featureIdx);
-                        for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
-                            final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
-                            StatsEvent.Builder e = StatsEvent.newBuilder();
-                            e.setAtomId(atomTag);
-                            e.writeInt(uid);
-                            e.writeString(packageOps.getPackageName());
-                            e.writeString(featureOps.getFeatureId());
-                            e.writeString(op.getOpName());
-                            e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
-                            e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
-                            e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
-                            e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
-                            e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
-                            e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
-
-                            String perm = AppOpsManager.opToPermission(op.getOpCode());
-                            if (perm == null) {
-                                e.writeBoolean(false);
-                            } else {
-                                PermissionInfo permInfo;
-                                try {
-                                    permInfo = mContext.getPackageManager().getPermissionInfo(perm,
-                                            0);
-                                    e.writeBoolean(
-                                            permInfo.getProtection() == PROTECTION_DANGEROUS);
-                                } catch (PackageManager.NameNotFoundException exception) {
-                                    e.writeBoolean(false);
-                                }
-                            }
-                            pulledData.add(e.build());
-                        }
-
-                    }
-                }
+            if (mAppOpsSamplingRate == 0) {
+                mAppOpsSamplingRate = constrain((5000 * 100) / estimateAppOpsSize(), 1, 100);
             }
+            processHistoricalOps(histOps, atomTag, pulledData);
         } catch (Throwable t) {
             // TODO: catch exceptions at a more granular level
             Slog.e(TAG, "Could not read appops", t);
@@ -3003,6 +2934,111 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    private int estimateAppOpsSize() throws Exception {
+        AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+
+        CompletableFuture<HistoricalOps> ops = new CompletableFuture<>();
+        HistoricalOpsRequest histOpsRequest =
+                new HistoricalOpsRequest.Builder(
+                        Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
+                        Long.MAX_VALUE).setFlags(
+                        OP_FLAGS_PULLED).build();
+        appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+        HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
+                TimeUnit.MILLISECONDS);
+        return processHistoricalOps(histOps, FrameworkStatsLog.APP_FEATURES_OPS, null);
+    }
+
+    int processHistoricalOps(HistoricalOps histOps, int atomTag, List<StatsEvent> pulledData) {
+        int counter = 0;
+        for (int uidIdx = 0; uidIdx < histOps.getUidCount(); uidIdx++) {
+            final HistoricalUidOps uidOps = histOps.getUidOpsAt(uidIdx);
+            final int uid = uidOps.getUid();
+            for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
+                final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
+                if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+                    for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
+                            featureIdx++) {
+                        final AppOpsManager.HistoricalFeatureOps featureOps =
+                                packageOps.getFeatureOpsAt(featureIdx);
+                        for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
+                            final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
+                            counter += processHistoricalOp(op, atomTag, pulledData, uid,
+                                    packageOps.getPackageName(), featureOps.getFeatureId());
+                        }
+                    }
+                } else if (atomTag == FrameworkStatsLog.APP_OPS) {
+                    for (int opIdx = 0; opIdx < packageOps.getOpCount(); opIdx++) {
+                        final AppOpsManager.HistoricalOp op = packageOps.getOpAt(opIdx);
+                        counter += processHistoricalOp(op, atomTag, pulledData, uid,
+                                packageOps.getPackageName(), null);
+                    }
+                }
+            }
+        }
+        return counter;
+    }
+
+    private int processHistoricalOp(AppOpsManager.HistoricalOp op, int atomTag,
+            @Nullable List<StatsEvent> pulledData, int uid, String packageName,
+            @Nullable String feature) {
+        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+            if (pulledData == null) { // this is size estimation call
+                if (op.getForegroundAccessCount(OP_FLAGS_PULLED) + op.getBackgroundAccessCount(
+                        OP_FLAGS_PULLED) == 0) {
+                    return 0;
+                } else {
+                    return 32 + packageName.length() + (feature == null ? 1 : feature.length());
+                }
+            } else {
+                if (abs((op.getOpCode() + feature + packageName).hashCode() + RANDOM_SEED) % 100
+                        >= mAppOpsSamplingRate) {
+                    return 0;
+                }
+            }
+        }
+
+        StatsEvent.Builder e = StatsEvent.newBuilder();
+        e.setAtomId(atomTag);
+        e.writeInt(uid);
+        e.writeString(packageName);
+        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+            e.writeString(feature);
+        }
+        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+            e.writeString(op.getOpName());
+        } else {
+            e.writeInt(op.getOpCode());
+        }
+        e.writeLong(op.getForegroundAccessCount(OP_FLAGS_PULLED));
+        e.writeLong(op.getBackgroundAccessCount(OP_FLAGS_PULLED));
+        e.writeLong(op.getForegroundRejectCount(OP_FLAGS_PULLED));
+        e.writeLong(op.getBackgroundRejectCount(OP_FLAGS_PULLED));
+        e.writeLong(op.getForegroundAccessDuration(OP_FLAGS_PULLED));
+        e.writeLong(op.getBackgroundAccessDuration(OP_FLAGS_PULLED));
+
+        String perm = AppOpsManager.opToPermission(op.getOpCode());
+        if (perm == null) {
+            e.writeBoolean(false);
+        } else {
+            PermissionInfo permInfo;
+            try {
+                permInfo = mContext.getPackageManager().getPermissionInfo(
+                        perm,
+                        0);
+                e.writeBoolean(
+                        permInfo.getProtection() == PROTECTION_DANGEROUS);
+            } catch (PackageManager.NameNotFoundException exception) {
+                e.writeBoolean(false);
+            }
+        }
+        if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+            e.writeInt(mAppOpsSamplingRate);
+        }
+        pulledData.add(e.build());
+        return 0;
+    }
+
     int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) {
         final long token = Binder.clearCallingIdentity();
         try {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index feb3e06..84cd4cf 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -60,6 +60,7 @@
 import com.android.internal.util.DumpUtils;
 import com.android.internal.view.AppearanceRegion;
 import com.android.server.LocalServices;
+import com.android.server.UiThread;
 import com.android.server.notification.NotificationDelegate;
 import com.android.server.policy.GlobalActionsProvider;
 import com.android.server.power.ShutdownThread;
@@ -1118,7 +1119,7 @@
     }
 
     private void notifyBarAttachChanged() {
-        mHandler.post(() -> {
+        UiThread.getHandler().post(() -> {
             if (mGlobalActionListener == null) return;
             mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
         });
diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index 73bb4bf..948439d 100644
--- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Binder;
 import android.util.EventLog;
 import android.util.Slog;
 
@@ -134,7 +135,12 @@
 
     private BufferedInputStream getAltContent(Context c, Intent i) throws IOException {
         Uri content = getContentFromIntent(i);
-        return new BufferedInputStream(c.getContentResolver().openInputStream(content));
+        Binder.allowBlockingForCurrentThread();
+        try {
+            return new BufferedInputStream(c.getContentResolver().openInputStream(content));
+        } finally {
+            Binder.defaultBlockingForCurrentThread();
+        }
     }
 
     private byte[] getCurrentContent() {
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index d7a80bf..68224b5 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -27,7 +27,6 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
-import android.app.Service;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -127,7 +126,7 @@
     public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
             WindowsForAccessibilityCallback callback) {
         if (callback != null) {
-            final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+            final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
             if (dc == null) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7a30211..b6ad241 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -200,6 +200,7 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.ACTIVITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
@@ -3150,7 +3151,7 @@
 
         // Reset the last saved PiP snap fraction on removal.
         mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
-
+        mWmService.mEmbeddedWindowController.onActivityRemoved(this);
         mRemovingFromDisplay = false;
     }
 
@@ -7450,6 +7451,11 @@
     }
 
     @Override
+    long getProtoFieldId() {
+        return ACTIVITY;
+    }
+
+    @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         // Critical log level logs only visible elements to mitigate performance overheard
@@ -7620,7 +7626,7 @@
         return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
                 record.mAdapter.mCapturedLeash, !fillsParent(),
                 mainWindow.mWinAnimator.mLastClipRect, insets,
-                getPrefixOrderIndex(), record.mAdapter.mPosition,
+                getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds,
                 record.mAdapter.mStackBounds, task.getWindowConfiguration(),
                 false /*isNotInRecents*/,
                 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 420675c..9bad799 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -90,7 +90,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.TaskProto.ACTIVITIES;
 import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
 import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
 import static com.android.server.wm.TaskProto.BOUNDS;
@@ -109,7 +108,6 @@
 import static com.android.server.wm.TaskProto.ROOT_TASK_ID;
 import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
 import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
-import static com.android.server.wm.TaskProto.TASKS;
 import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -649,14 +647,6 @@
 
         if (prevWindowingMode != getWindowingMode()) {
             mDisplayContent.onStackWindowingModeChanged(this);
-
-            if (inSplitScreenSecondaryWindowingMode()) {
-                // When the stack is resized due to entering split screen secondary, offset the
-                // windows to compensate for the new stack position.
-                forAllWindows(w -> {
-                    w.mWinAnimator.setOffsetPositionForStackResize(true);
-                }, true);
-            }
         }
 
         final DisplayContent display = getDisplay();
@@ -2395,8 +2385,10 @@
         }
         Task task = null;
         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, rTask);
+                    (ar) -> !ar.finishing && ar.occludesParent(), true, 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
@@ -3883,9 +3875,10 @@
             return;
         }
         if (mTile != null) {
-            reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+            // don't use reparentSurfaceControl because we need to bypass taskorg check
+            mSurfaceAnimator.reparent(getPendingTransaction(), mTile.getSurfaceControl());
         } else if (mTile == null && origTile != null) {
-            reparentSurfaceControl(getPendingTransaction(), getParentSurfaceControl());
+            mSurfaceAnimator.reparent(getPendingTransaction(), getParentSurfaceControl());
         }
     }
 
@@ -3918,17 +3911,6 @@
         proto.write(DISPLAY_ID, getDisplayId());
         proto.write(ROOT_TASK_ID, getRootTaskId());
 
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final WindowContainer child = mChildren.get(i);
-            if (child instanceof Task) {
-                child.dumpDebug(proto, TASKS, logLevel);
-            } else if (child instanceof ActivityRecord) {
-                child.dumpDebug(proto, ACTIVITIES, logLevel);
-            } else {
-                throw new IllegalStateException("Unknown child type: " + child);
-            }
-        }
-
         if (mResumedActivity != null) {
             mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 984ae21..c7a1391 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -29,7 +29,6 @@
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.WaitResult.LAUNCH_STATE_COLD;
 import static android.app.WaitResult.LAUNCH_STATE_HOT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_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;
@@ -178,6 +177,9 @@
     private Intent mNewTaskIntent;
     private ActivityStack mSourceStack;
     private ActivityStack mTargetStack;
+    // The task that the last activity was started into. We currently reset the actual start
+    // activity's task and as a result may not have a reference to the task in all cases
+    private Task mTargetTask;
     private boolean mMovedToFront;
     private boolean mNoAnimation;
     private boolean mKeepCurTransition;
@@ -545,6 +547,7 @@
         mNewTaskIntent = starter.mNewTaskIntent;
         mSourceStack = starter.mSourceStack;
 
+        mTargetTask = starter.mTargetTask;
         mTargetStack = starter.mTargetStack;
         mMovedToFront = starter.mMovedToFront;
         mNoAnimation = starter.mNoAnimation;
@@ -1368,7 +1371,10 @@
         // it waits for the new activity to become visible instead, {@link #waitResultIfNeeded}.
         mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
 
-        if (startedActivityStack == null) {
+        final Task targetTask = r.getTask() != null
+                ? r.getTask()
+                : mTargetTask;
+        if (startedActivityStack == null || targetTask == null) {
             return;
         }
 
@@ -1379,19 +1385,10 @@
             // The activity was already running so it wasn't started, but either brought to the
             // front or the new intent was delivered to it since it was already in front. Notify
             // anyone interested in this piece of information.
-            switch (startedActivityStack.getWindowingMode()) {
-                case WINDOWING_MODE_PINNED:
-                    mService.getTaskChangeNotificationController().notifyPinnedActivityRestartAttempt(
-                            clearedTask);
-                    break;
-                case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
-                    final ActivityStack homeStack =
-                            startedActivityStack.getDisplay().getOrCreateRootHomeTask();
-                    if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) {
-                        mService.mWindowManager.showRecentApps();
-                    }
-                    break;
-            }
+            final ActivityStack homeStack = targetTask.getDisplayContent().getRootHomeTask();
+            final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+            mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
+                    targetTask.getTaskInfo(), homeTaskVisible, clearedTask);
         }
     }
 
@@ -1517,6 +1514,7 @@
         // Compute if there is an existing task that should be used for.
         final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
         final boolean newTask = targetTask == null;
+        mTargetTask = targetTask;
 
         computeLaunchParams(r, sourceRecord, targetTask);
 
@@ -1570,10 +1568,16 @@
 
         mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
                 mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
-        mService.getPackageManagerInternalLocked().grantImplicitAccess(
-                mStartActivity.mUserId, mIntent,
-                UserHandle.getAppId(mStartActivity.info.applicationInfo.uid), mCallingUid,
-                true /*direct*/);
+        if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
+            // we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
+            final PackageManagerInternal pmInternal =
+                    mService.getPackageManagerInternalLocked();
+            final int resultToUid = pmInternal.getPackageUidInternal(
+                            mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
+            pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
+                    UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
+                    resultToUid /*visible*/, true /*direct*/);
+        }
         if (newTask) {
             EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
                     mStartActivity.getTask().mTaskId);
@@ -2012,6 +2016,7 @@
         mSourceStack = null;
 
         mTargetStack = null;
+        mTargetTask = null;
         mMovedToFront = false;
         mNoAnimation = false;
         mKeepCurTransition = false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 911812b..21d300a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -288,6 +288,7 @@
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -680,12 +681,15 @@
         }
 
         @Override
-        public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
-            if (mFontScaleUri.equals(uri)) {
-                updateFontScaleIfNeeded(userId);
-            } else if (mHideErrorDialogsUri.equals(uri)) {
-                synchronized (mGlobalLock) {
-                    updateShouldShowDialogsLocked(getGlobalConfiguration());
+        public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
+                @UserIdInt int userId) {
+            for (Uri uri : uris) {
+                if (mFontScaleUri.equals(uri)) {
+                    updateFontScaleIfNeeded(userId);
+                } else if (mHideErrorDialogsUri.equals(uri)) {
+                    synchronized (mGlobalLock) {
+                        updateShouldShowDialogsLocked(getGlobalConfiguration());
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index 94decc7..c18ed7d 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -114,7 +114,6 @@
         return st.addToSync(wc);
     }
 
-    // TODO(b/148476626): TIMEOUTS!
     void setReady(int id) {
         final SyncState st = mPendingSyncs.get(id);
         st.setReady();
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 0d365b1..d9e41af 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -23,13 +23,10 @@
 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
 
 import static com.android.internal.util.Preconditions.checkState;
-import static com.android.server.wm.DisplayAreaChildProto.DISPLAY_AREA;
-import static com.android.server.wm.DisplayAreaChildProto.UNKNOWN;
-import static com.android.server.wm.DisplayAreaChildProto.WINDOW;
-import static com.android.server.wm.DisplayAreaProto.CHILDREN;
 import static com.android.server.wm.DisplayAreaProto.NAME;
 import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
 
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
@@ -111,24 +108,14 @@
         final long token = proto.start(fieldId);
         super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(NAME, mName);
-        for (int i = 0; i < getChildCount(); i++) {
-            final long childToken = proto.start(CHILDREN);
-            final T child = getChildAt(i);
-            if (child instanceof ActivityStack) {
-                // TODO(display-area): Dump stacks & tasks here, instead of in DisplayContent's
-                //  dumpDebug. For now, skip them here to avoid dumping them as UNKNOWN.
-            } else if (child instanceof WindowToken) {
-                ((WindowToken) child).dumpDebug(proto, WINDOW, logLevel);
-            } else if (child instanceof DisplayArea) {
-                child.dumpDebug(proto, DISPLAY_AREA, logLevel);
-            } else {
-                proto.write(UNKNOWN, child.getClass().getSimpleName());
-            }
-            proto.end(childToken);
-        }
         proto.end(token);
     }
 
+    @Override
+    long getProtoFieldId() {
+        return DISPLAY_AREA;
+    }
+
     /**
      * DisplayArea that contains WindowTokens, and orders them according to their type.
      */
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 55ce84e..36fdb2d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -94,6 +94,7 @@
 import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
+import static com.android.server.wm.DisplayContentProto.DISPLAY_READY;
 import static com.android.server.wm.DisplayContentProto.DPI;
 import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
 import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
@@ -105,7 +106,6 @@
 import static com.android.server.wm.DisplayContentProto.ROTATION;
 import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
 import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
-import static com.android.server.wm.DisplayContentProto.TASKS;
 import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -117,6 +117,7 @@
 import static com.android.server.wm.RootWindowContainer.TAG_STATES;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.DISPLAY_CONTENT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
@@ -2837,10 +2838,6 @@
 
         proto.write(ID, mDisplayId);
         mRootDisplayArea.dumpDebug(proto, ROOT_DISPLAY_AREA, logLevel);
-        for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
-            final ActivityStack stack = mTaskContainers.getChildAt(i);
-            stack.dumpDebug(proto, TASKS, logLevel);
-        }
         for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) {
             final WindowToken windowToken = mOverlayContainers.getChildAt(i);
             windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel);
@@ -2875,11 +2872,17 @@
         } else {
             proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID);
         }
+        proto.write(DISPLAY_READY, isReady());
 
         proto.end(token);
     }
 
     @Override
+    long getProtoFieldId() {
+        return DISPLAY_CONTENT;
+    }
+
+    @Override
     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
         pw.print(prefix);
@@ -4931,6 +4934,12 @@
                 scheduleAnimation();
             }
         }
+
+        @Override
+        boolean shouldMagnify() {
+            // Omitted from Screen-Magnification
+            return false;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
index 884f769..484a5a8 100644
--- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java
+++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java
@@ -17,11 +17,15 @@
 package com.android.server.wm;
 
 
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.annotation.Nullable;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArrayMap;
+import android.util.Slog;
 import android.view.IWindow;
 import android.view.InputApplicationHandle;
 
@@ -33,12 +37,15 @@
  * the host window to send pointerDownOutsideFocus.
  */
 class EmbeddedWindowController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "EmbeddedWindowController" : TAG_WM;
     /* maps input token to an embedded window */
     private ArrayMap<IBinder /*input token */, EmbeddedWindow> mWindows = new ArrayMap<>();
-    private final Object mWmLock;
+    private final Object mGlobalLock;
+    private final ActivityTaskManagerService mAtmService;
 
-    EmbeddedWindowController(Object wmLock) {
-        mWmLock = wmLock;
+    EmbeddedWindowController(ActivityTaskManagerService atmService) {
+        mAtmService = atmService;
+        mGlobalLock = atmService.getGlobalLock();
     }
 
     /**
@@ -46,13 +53,14 @@
      *
      * @param inputToken input channel token passed in by the embedding process when it requests
      *                   the server to add an input channel to the embedded surface.
-     * @param embeddedWindow An {@link EmbeddedWindow} object to add to this controller.
+     * @param window An {@link EmbeddedWindow} object to add to this controller.
      */
-    void add(IBinder inputToken, EmbeddedWindow embeddedWindow) {
+    void add(IBinder inputToken, EmbeddedWindow window) {
         try {
-            mWindows.put(inputToken, embeddedWindow);
-            embeddedWindow.mClient.asBinder().linkToDeath(()-> {
-                synchronized (mWmLock) {
+            mWindows.put(inputToken, window);
+            updateProcessController(window);
+            window.mClient.asBinder().linkToDeath(()-> {
+                synchronized (mGlobalLock) {
                     mWindows.remove(inputToken);
                 }
             }, 0);
@@ -62,6 +70,23 @@
         }
     }
 
+    /**
+     * Track the host activity in the embedding process so we can determine if the
+     * process is currently showing any UI to the user.
+     */
+    private void updateProcessController(EmbeddedWindow window) {
+        if (window.mHostActivityRecord == null) {
+            return;
+        }
+        final WindowProcessController processController =
+                mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
+        if (processController == null) {
+            Slog.w(TAG, "Could not find the embedding process.");
+        } else {
+            processController.addHostActivity(window.mHostActivityRecord);
+        }
+    }
+
     WindowState getHostWindow(IBinder inputToken) {
         EmbeddedWindow embeddedWindow = mWindows.get(inputToken);
         return embeddedWindow != null ? embeddedWindow.mHostWindowState : null;
@@ -76,7 +101,7 @@
         }
     }
 
-    void removeWindowsWithHost(WindowState host) {
+    void onWindowRemoved(WindowState host) {
         for (int i = mWindows.size() - 1; i >= 0; i--) {
             if (mWindows.valueAt(i).mHostWindowState == host) {
                 mWindows.removeAt(i);
@@ -88,9 +113,23 @@
         return mWindows.get(inputToken);
     }
 
+    void onActivityRemoved(ActivityRecord activityRecord) {
+        for (int i = mWindows.size() - 1; i >= 0; i--) {
+            final EmbeddedWindow window = mWindows.valueAt(i);
+            if (window.mHostActivityRecord == activityRecord) {
+                final WindowProcessController processController =
+                        mAtmService.getProcessController(window.mOwnerPid, window.mOwnerUid);
+                if (processController != null) {
+                    processController.removeHostActivity(activityRecord);
+                }
+            }
+        }
+    }
+
     static class EmbeddedWindow {
         final IWindow mClient;
         @Nullable final WindowState mHostWindowState;
+        @Nullable final ActivityRecord mHostActivityRecord;
         final int mOwnerUid;
         final int mOwnerPid;
 
@@ -107,6 +146,8 @@
                 int ownerPid) {
             mClient = clientToken;
             mHostWindowState = hostWindowState;
+            mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
+                    : null;
             mOwnerUid = ownerUid;
             mOwnerPid = ownerPid;
         }
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 58aefdc..ada6d47 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -274,7 +274,7 @@
             // window crop of the surface controls (including the leash) until the client finishes
             // drawing the new frame of the new orientation. Although we cannot defer the reparent
             // operation, it is fine, because reparent won't cause any visual effect.
-            final SurfaceControl barrier = mWin.getDeferTransactionBarrier();
+            final SurfaceControl barrier = mWin.getClientViewRootSurface();
             t.deferTransactionUntil(mWin.getSurfaceControl(), barrier, frameNumber);
             t.deferTransactionUntil(leash, barrier, frameNumber);
         }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index e1906da..6ff029b 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -18,10 +18,14 @@
 
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
+import static android.view.InsetsState.ITYPE_INVALID;
 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.ViewRootImpl.sNewInsetsMode;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -32,6 +36,7 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowManager;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -74,15 +79,40 @@
      * @param target The client we dispatch the state to.
      * @return The state stripped of the necessary information.
      */
-    InsetsState getInsetsForDispatch(WindowState target) {
+    InsetsState getInsetsForDispatch(@NonNull WindowState target) {
         final InsetsSourceProvider provider = target.getControllableInsetProvider();
         if (provider == null) {
             return mState;
         }
+        final @InternalInsetsType int type = provider.getSource().getType();
+        return getInsetsForType(type);
+    }
 
+    InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
+        final @InternalInsetsType int type = getInsetsTypeForWindowType(attrs.type);
+        if (type == ITYPE_INVALID) {
+            return mState;
+        }
+        return getInsetsForType(type);
+    }
+
+    @InternalInsetsType
+    private static int getInsetsTypeForWindowType(int type) {
+        switch(type) {
+            case TYPE_STATUS_BAR:
+                return ITYPE_STATUS_BAR;
+            case TYPE_NAVIGATION_BAR:
+                return ITYPE_NAVIGATION_BAR;
+            case TYPE_INPUT_METHOD:
+                return ITYPE_IME;
+            default:
+                return ITYPE_INVALID;
+        }
+    }
+
+    private InsetsState getInsetsForType(@InternalInsetsType int type) {
         final InsetsState state = new InsetsState();
         state.set(mState);
-        final int type = provider.getSource().getType();
         state.removeSource(type);
 
         // Navigation bar doesn't get influenced by anything else
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5cd0169..3e5cb50 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -820,15 +820,19 @@
         private @AnimationType int mLastAnimationType;
         private final boolean mIsRecentTaskInvisible;
         private RemoteAnimationTarget mTarget;
-        private final Point mPosition = new Point();
         private final Rect mBounds = new Rect();
+        // The bounds of the target relative to its parent.
+        private Rect mLocalBounds = new Rect();
 
         TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
             mTask = task;
             mIsRecentTaskInvisible = isRecentTaskInvisible;
-            final WindowContainer container = mTask.getParent();
-            mBounds.set(container.getDisplayedBounds());
-            mPosition.set(mBounds.left, mBounds.top);
+            mBounds.set(mTask.getDisplayedBounds());
+
+            mLocalBounds.set(mBounds);
+            Point tmpPos = new Point();
+            mTask.getRelativeDisplayedPosition(tmpPos);
+            mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
         }
 
         RemoteAnimationTarget createRemoteAnimationTarget() {
@@ -847,8 +851,9 @@
                     : MODE_CLOSING;
             mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
                     !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
-                    insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
-                    mTask.getWindowConfiguration(), mIsRecentTaskInvisible, null, null);
+                    insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
+                    mLocalBounds, mBounds, mTask.getWindowConfiguration(),
+                    mIsRecentTaskInvisible, null, null);
             return mTarget;
         }
 
@@ -862,8 +867,8 @@
                 @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
             // Restore z-layering, position and stack crop until client has a chance to modify it.
             t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
-            t.setPosition(animationLeash, mPosition.x, mPosition.y);
-            mTmpRect.set(mBounds);
+            t.setPosition(animationLeash, mLocalBounds.left, mLocalBounds.top);
+            mTmpRect.set(mLocalBounds);
             mTmpRect.offsetTo(0, 0);
             t.setWindowCrop(animationLeash, mTmpRect);
             mCapturedLeash = animationLeash;
@@ -897,7 +902,7 @@
                 pw.print(prefix); pw.println("Target: null");
             }
             pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
-            pw.println("mPosition=" + mPosition);
+            pw.println("mLocalBounds=" + mLocalBounds);
             pw.println("mBounds=" + mBounds);
             pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
         }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 0eb9daf..35f8d34 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -80,16 +80,17 @@
      *
      * @param windowContainer The windows to animate.
      * @param position The position app bounds, in screen coordinates.
+     * @param localBounds The bounds of the app relative to its parent.
      * @param stackBounds The stack bounds of the app relative to position.
      * @param startBounds The stack bounds before the transition, in screen coordinates
      * @return The record representing animation(s) to run on the app.
      */
     RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
-            Point position, Rect stackBounds, Rect startBounds) {
+            Point position, Rect localBounds, Rect stackBounds, Rect startBounds) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
                 windowContainer);
-        final RemoteAnimationRecord adapters =
-                new RemoteAnimationRecord(windowContainer, position, stackBounds, startBounds);
+        final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
+                localBounds, stackBounds, startBounds);
         mPendingAnimations.add(adapters);
         return adapters;
     }
@@ -355,17 +356,18 @@
         final WindowContainer mWindowContainer;
         final Rect mStartBounds;
 
-        RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect endBounds,
-                Rect startBounds) {
+        RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
+                Rect endBounds, Rect startBounds) {
             mWindowContainer = windowContainer;
-            mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, endBounds);
+            mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds);
             if (startBounds != null) {
                 mStartBounds = new Rect(startBounds);
                 mTmpRect.set(startBounds);
                 mTmpRect.offsetTo(0, 0);
                 if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
                     mThumbnailAdapter =
-                            new RemoteAnimationAdapterWrapper(this, new Point(0, 0), mTmpRect);
+                            new RemoteAnimationAdapterWrapper(this, new Point(0, 0), localBounds,
+                                    mTmpRect);
                 }
             } else {
                 mStartBounds = null;
@@ -401,12 +403,14 @@
         private OnAnimationFinishedCallback mCapturedFinishCallback;
         private @AnimationType int mAnimationType;
         final Point mPosition = new Point();
+        final Rect mLocalBounds;
         final Rect mStackBounds = new Rect();
 
         RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
-                Rect stackBounds) {
+                Rect localBounds, Rect stackBounds) {
             mRecord = record;
             mPosition.set(position.x, position.y);
+            mLocalBounds = localBounds;
             mStackBounds.set(stackBounds);
         }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 74c3044..15a49a7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -66,11 +66,9 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
-import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
 import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT;
 import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER;
 import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES;
-import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
 import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
 import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
 import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
@@ -1278,18 +1276,6 @@
 
         final long token = proto.start(fieldId);
         super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
-        if (mWmService.mDisplayReady) {
-            final int count = mChildren.size();
-            for (int i = 0; i < count; ++i) {
-                final DisplayContent displayContent = mChildren.get(i);
-                displayContent.dumpDebug(proto, DISPLAYS, logLevel);
-            }
-        }
-        if (logLevel == WindowTraceLogLevel.ALL) {
-            forAllWindows((w) -> {
-                w.dumpDebug(proto, WINDOWS, logLevel);
-            }, true);
-        }
 
         mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
         proto.write(IS_HOME_RECENTS_COMPONENT,
@@ -2265,8 +2251,8 @@
                 final ActivityStack focusedStack = display.getFocusedStack();
                 if (focusedStack != null) {
                     result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
-                } else if (targetStack == null && display.getStackCount() == 0) {
-                    result |= resumeHomeActivity(null /* prev */, "empty-display",
+                } else if (targetStack == null) {
+                    result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
                             display.mDisplayId);
                 }
             }
diff --git a/services/core/java/com/android/server/wm/SeamlessRotator.java b/services/core/java/com/android/server/wm/SeamlessRotator.java
index 024da88..8e1c632 100644
--- a/services/core/java/com/android/server/wm/SeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/SeamlessRotator.java
@@ -118,9 +118,9 @@
         finish(t, win);
         if (win.mWinAnimator.mSurfaceController != null && !timeout) {
             t.deferTransactionUntil(win.mSurfaceControl,
-                    win.getDeferTransactionBarrier(), win.getFrameNumber());
+                    win.getClientViewRootSurface(), win.getFrameNumber());
             t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
-                    win.getDeferTransactionBarrier(), win.getFrameNumber());
+                    win.getClientViewRootSurface(), win.getFrameNumber());
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 88d4fb3..b2db99b 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -85,6 +85,7 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.TASK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -3970,12 +3971,12 @@
 
     boolean isControlledByTaskOrganizer() {
         final Task rootTask = getRootTask();
-        return rootTask == this && rootTask.mTaskOrganizer != null
-                // TODO(task-hierarchy): Figure out how to control nested tasks.
-                // For now, if this is in a tile let WM drive.
-                && !(rootTask instanceof TaskTile)
-                && !(rootTask instanceof ActivityStack
-                        && ((ActivityStack) rootTask).getTile() != null);
+        // 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) {
+            return false;
+        }
+        return rootTask == this && rootTask.mTaskOrganizer != null;
     }
 
     @Override
@@ -4121,4 +4122,9 @@
     SurfaceControl.Transaction getMainWindowSizeChangeTransaction() {
         return mMainWindowSizeChangeTransaction;
     }
+
+    @Override
+    long getProtoFieldId() {
+        return TASK;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 96a9127..e4f10d9 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -30,13 +30,15 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 
+import com.android.internal.os.SomeArgs;
+
 import java.util.ArrayList;
 
 class TaskChangeNotificationController {
     private static final int LOG_STACK_STATE_MSG = 1;
     private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
     private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
-    private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
+    private static final int NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
     private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
     private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
     private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
@@ -118,8 +120,10 @@
         l.onActivityUnpinned();
     };
 
-    private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
-        l.onPinnedActivityRestartAttempt(m.arg1 != 0);
+    private final TaskStackConsumer mNotifyActivityRestartAttempt = (l, m) -> {
+        SomeArgs args = (SomeArgs) m.obj;
+        l.onActivityRestartAttempt((RunningTaskInfo) args.arg1, args.argi1 != 0,
+                args.argi2 != 0);
     };
 
     private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> {
@@ -220,8 +224,8 @@
                 case NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyActivityUnpinned, msg);
                     break;
-                case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
-                    forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg);
+                case NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyActivityRestartAttempt, msg);
                     break;
                 case NOTIFY_FORCED_RESIZABLE_MSG:
                     forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
@@ -266,6 +270,9 @@
                     forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
                     break;
             }
+            if (msg.obj instanceof SomeArgs) {
+                ((SomeArgs) msg.obj).recycle();
+            }
         }
     }
 
@@ -358,15 +365,18 @@
 
     /**
      * Notifies all listeners when an attempt was made to start an an activity that is already
-     * running in the pinned stack and the activity was not actually started, but the task is
-     * either brought to the front or a new Intent is delivered to it.
+     * running, but the task is either brought to the front or a new Intent is delivered to it.
      */
-    void notifyPinnedActivityRestartAttempt(boolean clearedTask) {
-        mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
-        final Message msg =
-                mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
-                        clearedTask ? 1 : 0, 0);
-        forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
+    void notifyActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+            boolean clearedTask) {
+        mHandler.removeMessages(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+        final SomeArgs args = SomeArgs.obtain();
+        args.arg1 = task;
+        args.argi1 = homeTaskVisible ? 1 : 0;
+        args.argi2 = clearedTask ? 1 : 0;
+        final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
+                        args);
+        forAllLocalListeners(mNotifyActivityRestartAttempt, msg);
         msg.sendToTarget();
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index b38c18b..4093fe5 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -128,7 +128,7 @@
 
         void removeTask(Task t) {
             try {
-                mOrganizer.taskVanished(t.getRemoteToken());
+                mOrganizer.taskVanished(t.getTaskInfo());
             } catch (Exception e) {
                 Slog.e(TAG, "Exception sending taskVanished callback" + e);
             }
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index b5892b9..f046e8a 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -35,7 +35,6 @@
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import android.annotation.NonNull;
-import android.app.IActivityTaskManager;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -48,7 +47,6 @@
 import android.util.Slog;
 import android.view.BatchedInputEventReceiver;
 import android.view.Choreographer;
-import android.view.Display;
 import android.view.InputApplicationHandle;
 import android.view.InputChannel;
 import android.view.InputDevice;
@@ -75,10 +73,8 @@
     public static final int RESIZING_HINT_DURATION_MS = 0;
 
     private final WindowManagerService mService;
-    private final IActivityTaskManager mActivityManager;
     private WindowPositionerEventReceiver mInputEventReceiver;
     private DisplayContent mDisplayContent;
-    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
     private Rect mTmpRect = new Rect();
     private int mMinVisibleWidth;
     private int mMinVisibleHeight;
@@ -151,11 +147,8 @@
                         if (!mTmpRect.equals(mWindowDragBounds)) {
                             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                                     "wm.TaskPositioner.resizeTask");
-                            try {
-                                mActivityManager.resizeTask(
-                                        mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
-                            } catch (RemoteException e) {
-                            }
+                            mService.mAtmService.resizeTask(
+                                    mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
                             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                         }
                     } break;
@@ -181,14 +174,12 @@
                         endDragLocked();
                         mTask.getDimBounds(mTmpRect);
                     }
-                    try {
-                        if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
-                            // We were using fullscreen surface during resizing. Request
-                            // resizeTask() one last time to restore surface to window size.
-                            mActivityManager.resizeTask(
-                                    mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
-                        }
-                    } catch(RemoteException e) {}
+                    if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
+                        // We were using fullscreen surface during resizing. Request
+                        // resizeTask() one last time to restore surface to window size.
+                        mService.mAtmService.resizeTask(
+                                mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
+                    }
 
                     // Post back to WM to handle clean-ups. We still need the input
                     // event handler for the last finishInputEvent()!
@@ -203,15 +194,10 @@
         }
     }
 
+    /** Use {@link #create(WindowManagerService)} instead. */
     @VisibleForTesting
-    TaskPositioner(WindowManagerService service, IActivityTaskManager activityManager) {
-        mService = service;
-        mActivityManager = activityManager;
-    }
-
-    /** Use {@link #create(WindowManagerService)} instead **/
     TaskPositioner(WindowManagerService service) {
-        this(service, service.mActivityTaskManager);
+        mService = service;
     }
 
     @VisibleForTesting
@@ -224,8 +210,6 @@
      * @param win The window which will be dragged.
      */
     void register(DisplayContent displayContent, @NonNull WindowState win) {
-        final Display display = displayContent.getDisplay();
-
         if (DEBUG_TASK_POSITIONING) {
             Slog.d(TAG, "Registering task positioner");
         }
@@ -236,7 +220,6 @@
         }
 
         mDisplayContent = displayContent;
-        display.getMetrics(mDisplayMetrics);
         final InputChannel[] channels = InputChannel.openInputChannelPair(TAG);
         mServerChannel = channels[0];
         mClientChannel = channels[1];
@@ -251,7 +234,8 @@
         mDragApplicationHandle.dispatchingTimeoutNanos =
                 WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
 
-        mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle, display.getDisplayId());
+        mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
+                displayContent.getDisplayId());
         mDragWindowHandle.name = TAG;
         mDragWindowHandle.token = mServerChannel.getToken();
         mDragWindowHandle.layoutParamsFlags = 0;
@@ -271,13 +255,13 @@
         // The drag window cannot receive new touches.
         mDragWindowHandle.touchableRegion.setEmpty();
 
-        // The drag window covers the entire display
-        mDragWindowHandle.frameLeft = 0;
-        mDragWindowHandle.frameTop = 0;
-        final Point p = new Point();
-        display.getRealSize(p);
-        mDragWindowHandle.frameRight = p.x;
-        mDragWindowHandle.frameBottom = p.y;
+        // The drag window covers the entire display.
+        final Rect displayBounds = mTmpRect;
+        displayContent.getBounds(mTmpRect);
+        mDragWindowHandle.frameLeft = displayBounds.left;
+        mDragWindowHandle.frameTop = displayBounds.top;
+        mDragWindowHandle.frameRight = displayBounds.right;
+        mDragWindowHandle.frameBottom = displayBounds.bottom;
 
         // Pause rotations before a drag.
         ProtoLog.d(WM_DEBUG_ORIENTATION, "Pausing rotation during re-position");
@@ -287,9 +271,10 @@
         mDisplayContent.getInputMonitor().updateInputWindowsImmediately();
         new SurfaceControl.Transaction().syncInputWindows().apply(true);
 
-        mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
-        mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
-        display.getRealSize(mMaxVisibleSize);
+        final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
+        mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
+        mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
+        mMaxVisibleSize.set(displayBounds.width(), displayBounds.height());
 
         mDragEnded = false;
 
@@ -341,8 +326,11 @@
         mWindow = null;
     }
 
-    void startDrag(boolean resize, boolean preserveOrientation, float startX,
-            float startY) {
+    /**
+     * Starts moving or resizing the task. This method should be only called from
+     * {@link TaskPositioningController#startPositioningLocked} or unit tests.
+     */
+    void startDrag(boolean resize, boolean preserveOrientation, float startX, float startY) {
         if (DEBUG_TASK_POSITIONING) {
             Slog.d(TAG, "startDrag: win=" + mWindow + ", resize=" + resize
                     + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", "
@@ -351,12 +339,9 @@
         // Use the bounds of the task which accounts for
         // multiple app windows. Don't use any bounds from win itself as it
         // may not be the same size as the task.
-        mTask.getBounds(mTmpRect);
-        startDrag(resize, preserveOrientation, startX, startY, mTmpRect);
-    }
+        final Rect startBounds = mTmpRect;
+        mTask.getBounds(startBounds);
 
-    protected void startDrag(boolean resize, boolean preserveOrientation,
-                   float startX, float startY, Rect startBounds) {
         mCtrlType = CTRL_NONE;
         mStartDragX = startX;
         mStartDragY = startY;
@@ -389,20 +374,13 @@
         // bounds yet. This will guarantee that the app starts the backdrop renderer before
         // configuration changes which could cause an activity restart.
         if (mResizing) {
-            synchronized (mService.mGlobalLock) {
-                notifyMoveLocked(startX, startY);
-            }
+            notifyMoveLocked(startX, startY);
 
-            // Perform the resize on the WMS handler thread when we don't have the WMS lock held
-            // to ensure that we don't deadlock WMS and AMS. Note that WindowPositionerEventReceiver
-            // callbacks are delivered on the same handler so this initial resize is always
-            // guaranteed to happen before subsequent drag resizes.
+            // The WindowPositionerEventReceiver callbacks are delivered on the same handler so this
+            // initial resize is always guaranteed to happen before subsequent drag resizes.
             mService.mH.post(() -> {
-                try {
-                    mActivityManager.resizeTask(
-                            mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
-                } catch (RemoteException e) {
-                }
+                mService.mAtmService.resizeTask(
+                        mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
             });
         }
 
@@ -417,7 +395,8 @@
     }
 
     /** Returns true if the move operation should be ended. */
-    private boolean notifyMoveLocked(float x, float y) {
+    @VisibleForTesting
+    boolean notifyMoveLocked(float x, float y) {
         if (DEBUG_TASK_POSITIONING) {
             Slog.d(TAG, "notifyMoveLocked: {" + x + "," + y + "}");
         }
@@ -429,12 +408,11 @@
         }
 
         // This is a moving or scrolling operation.
-        mTask.getStack().getDimBounds(mTmpRect);
-        // If a target window is covered by system bar, there is no way to move it again by touch.
-        // So we exclude them from stack bounds. and then it will be shown inside stable area.
-        Rect stableBounds = new Rect();
-        mDisplayContent.getStableRect(stableBounds);
-        mTmpRect.intersect(stableBounds);
+        // Only allow to move in stable area so the target window won't be covered by system bar.
+        // Though {@link Task#resolveOverrideConfiguration} should also avoid the case.
+        mDisplayContent.getStableRect(mTmpRect);
+        // The task may be put in a limited display area.
+        mTmpRect.intersect(mTask.getRootTask().getParent().getBounds());
 
         int nX = (int) x;
         int nY = (int) y;
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index bd70599..f467015 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -92,7 +92,7 @@
      */
     RemoteAnimationTarget createRemoteAnimationTarget() {
         mTarget = new RemoteAnimationTarget(-1, -1, getLeash(), false, null, null,
-                mWallpaperToken.getPrefixOrderIndex(), new Point(), null,
+                mWallpaperToken.getPrefixOrderIndex(), new Point(), null, null,
                 mWallpaperToken.getWindowConfiguration(), true, null, null);
         return mTarget;
     }
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 10d34b5..e8897e1 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -40,6 +40,7 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW_CONTAINER;
 import static com.android.server.wm.WindowContainerProto.CONFIGURATION_CONTAINER;
 import static com.android.server.wm.WindowContainerProto.ORIENTATION;
 import static com.android.server.wm.WindowContainerProto.SURFACE_ANIMATOR;
@@ -1819,9 +1820,25 @@
         if (mSurfaceAnimator.isAnimating()) {
             mSurfaceAnimator.dumpDebug(proto, SURFACE_ANIMATOR);
         }
+
+        // add children to proto
+        for (int i = 0; i < getChildCount(); i++) {
+            final long childToken = proto.start(WindowContainerProto.CHILDREN);
+            final E child = getChildAt(i);
+            child.dumpDebug(proto, child.getProtoFieldId(), logLevel);
+            proto.end(childToken);
+        }
         proto.end(token);
     }
 
+    /**
+     * @return a proto field id to identify where to add the derived class to the generic window
+     * container proto.
+     */
+    long getProtoFieldId() {
+        return WINDOW_CONTAINER;
+    }
+
     private ForAllWindowsConsumerWrapper obtainConsumerWrapper(Consumer<WindowState> consumer) {
         ForAllWindowsConsumerWrapper wrapper = mConsumerWrapperPool.acquire();
         if (wrapper == null) {
@@ -2086,9 +2103,11 @@
 
         // Delaying animation start isn't compatible with remote animations at all.
         if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
+            final Rect localBounds = new Rect(mTmpRect);
+            localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
             final RemoteAnimationController.RemoteAnimationRecord adapters =
-                    controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
-                            (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
+                    controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
+                            mTmpRect, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
             resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
         } else if (isChanging) {
             final float durationScale = mWmService.getTransitionAnimationScaleLocked();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3f4f629..42a66ad 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1287,7 +1287,7 @@
         mConstants.start(new HandlerExecutor(mH));
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
-        mEmbeddedWindowController = new EmbeddedWindowController(mGlobalLock);
+        mEmbeddedWindowController = new EmbeddedWindowController(mAtmService);
 
         mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
                 mContext.getResources());
@@ -1900,7 +1900,7 @@
         if (dc.mCurrentFocus == null) {
             dc.mWinRemovedSinceNullFocus.add(win);
         }
-        mEmbeddedWindowController.removeWindowsWithHost(win);
+        mEmbeddedWindowController.onWindowRemoved(win);
         mPendingRemove.remove(win);
         mResizingWindows.remove(win);
         updateNonSystemOverlayWindowsVisibilityIfNeeded(win, false /* surfaceShown */);
@@ -2610,7 +2610,8 @@
                 if (type == TYPE_WALLPAPER) {
                     new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens);
                 } else {
-                    new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens);
+                    new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens,
+                            false /* roundedCornerOverlay */, fromClientToken);
                 }
             }
         } finally {
@@ -4661,6 +4662,7 @@
         public static final int RECOMPUTE_FOCUS = 61;
         public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
         public static final int LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED = 63;
+        public static final int WINDOW_STATE_BLAST_SYNC_TIMEOUT = 64;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -5041,6 +5043,13 @@
                     }
                     break;
                 }
+                case WINDOW_STATE_BLAST_SYNC_TIMEOUT: {
+                    synchronized (mGlobalLock) {
+                      final WindowState ws = (WindowState) msg.obj;
+                      ws.finishDrawing(null);
+                    }
+                    break;
+                }
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -6126,7 +6135,7 @@
                 }
 
                 mRoot.forAllWindows((w) -> {
-                    if ((!visibleOnly || w.mWinAnimator.getShown())
+                    if ((!visibleOnly || w.isVisible())
                             && (!appsOnly || w.mActivityRecord != null)) {
                         windows.add(w);
                     }
@@ -8010,9 +8019,9 @@
     }
 
     @Override
-    public void getWindowInsets(WindowManager.LayoutParams attrs,
+    public boolean getWindowInsets(WindowManager.LayoutParams attrs,
             int displayId, Rect outContentInsets, Rect outStableInsets,
-            DisplayCutout.ParcelableWrapper displayCutout) {
+            DisplayCutout.ParcelableWrapper outDisplayCutout, InsetsState outInsetsState) {
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
@@ -8022,8 +8031,13 @@
                             + "could not be found!");
                 }
                 final WindowToken windowToken = dc.getWindowToken(attrs.token);
-                dc.getDisplayPolicy().getLayoutHint(attrs, windowToken, mTmpRect /* outFrame */,
-                        outContentInsets, outStableInsets, displayCutout);
+                final InsetsStateController insetsStateController =
+                        dc.getInsetsStateController();
+                outInsetsState.set(insetsStateController.getInsetsForWindowMetrics(attrs));
+
+                return dc.getDisplayPolicy().getLayoutHint(attrs, windowToken,
+                        mTmpRect /* outFrame */, outContentInsets, outStableInsets,
+                        outDisplayCutout);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 03dc4c9..833bb83 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -41,6 +41,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityThread;
 import android.app.IApplicationThread;
 import android.app.ProfilerInfo;
@@ -185,6 +186,13 @@
     // Registered display id as a listener to override config change
     private int mDisplayId;
     private ActivityRecord mConfigActivityRecord;
+    /**
+     * Activities that hosts some UI drawn by the current process. The activities live
+     * in another process. This is used to check if the process is currently showing anything
+     * visible to the user.
+     */
+    @Nullable
+    private final ArrayList<ActivityRecord> mHostActivities = new ArrayList<>();
 
     /** Whether our process is currently running a {@link RecentsAnimation} */
     private boolean mRunningRecentsAnimation;
@@ -672,6 +680,23 @@
                     return true;
                 }
             }
+            if (isEmbedded()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return {@code true} if this process is rendering content on to a window shown by
+     * another process.
+     */
+    private boolean isEmbedded() {
+        for (int i = mHostActivities.size() - 1; i >= 0; --i) {
+            final ActivityRecord r = mHostActivities.get(i);
+            if (r.isInterestingToUserLocked()) {
+                return true;
+            }
         }
         return false;
     }
@@ -814,6 +839,19 @@
         }
     }
 
+    /** Adds an activity that hosts UI drawn by the current process. */
+    void addHostActivity(ActivityRecord r) {
+        if (mHostActivities.contains(r)) {
+            return;
+        }
+        mHostActivities.add(r);
+    }
+
+    /** Removes an activity that hosts UI drawn by the current process. */
+    void removeHostActivity(ActivityRecord r) {
+        mHostActivities.remove(r);
+    }
+
     public interface ComputeOomAdjCallback {
         void onVisibleActivity();
         void onPausedActivity();
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 27f1ca0..fc28cd5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -118,6 +118,7 @@
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
@@ -137,6 +138,7 @@
 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;
@@ -145,7 +147,6 @@
 import static com.android.server.wm.WindowStateProto.ANIMATING_EXIT;
 import static com.android.server.wm.WindowStateProto.ANIMATOR;
 import static com.android.server.wm.WindowStateProto.ATTRIBUTES;
-import static com.android.server.wm.WindowStateProto.CHILD_WINDOWS;
 import static com.android.server.wm.WindowStateProto.DESTROYING;
 import static com.android.server.wm.WindowStateProto.DISPLAY_ID;
 import static com.android.server.wm.WindowStateProto.FINISHED_SEAMLESS_ROTATION_FRAME;
@@ -669,6 +670,8 @@
      */
     int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET;
 
+    static final int BLAST_TIMEOUT_DURATION = 5000; /* milliseconds */
+
     /**
      * @return The insets state as requested by the client, i.e. the dispatched insets state
      *         for which the visibilities are overridden with what the client requested.
@@ -3758,9 +3761,6 @@
         mSurfacePosition.dumpDebug(proto, SURFACE_POSITION);
         mWinAnimator.dumpDebug(proto, ANIMATOR);
         proto.write(ANIMATING_EXIT, mAnimatingExit);
-        for (int i = 0; i < mChildren.size(); i++) {
-            mChildren.get(i).dumpDebug(proto, CHILD_WINDOWS, logLevel);
-        }
         proto.write(REQUESTED_WIDTH, mRequestedWidth);
         proto.write(REQUESTED_HEIGHT, mRequestedHeight);
         proto.write(VIEW_VISIBILITY, mViewVisibility);
@@ -3779,6 +3779,11 @@
     }
 
     @Override
+    long getProtoFieldId() {
+        return WINDOW;
+    }
+
+    @Override
     public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
@@ -5660,8 +5665,8 @@
         return mSession.mPid == pid && isNonToastOrStarting() && isVisibleNow();
     }
 
-    SurfaceControl getDeferTransactionBarrier() {
-        return mWinAnimator.getDeferTransactionBarrier();
+    SurfaceControl getClientViewRootSurface() {
+        return mWinAnimator.getClientViewRootSurface();
     }
 
     @Override
@@ -5671,6 +5676,11 @@
         mWaitingListener = waitingListener;
         mWaitingSyncId = waitingId;
         mUsingBLASTSyncTransaction = true;
+
+        mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
+        mWmService.mH.sendNewMessageDelayed(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this,
+            BLAST_TIMEOUT_DURATION);
+
         return true;
     }
 
@@ -5678,6 +5688,8 @@
         if (!mUsingBLASTSyncTransaction) {
             return mWinAnimator.finishDrawingLocked(postDrawTransaction);
         }
+
+        mWmService.mH.removeMessages(WINDOW_STATE_BLAST_SYNC_TIMEOUT, this);
         if (postDrawTransaction == null) {
             postDrawTransaction = new SurfaceControl.Transaction();
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 81d0e3e..79dc536 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -383,8 +383,9 @@
             // Make sure to reparent any children of the new surface back to the preserved
             // surface before destroying it.
             if (mSurfaceController != null && mPendingDestroySurface != null) {
-                mPostDrawTransaction.reparentChildren(mSurfaceController.mSurfaceControl,
-                        mPendingDestroySurface.mSurfaceControl).apply();
+                mPostDrawTransaction.reparentChildren(
+                    mSurfaceController.getClientViewRootSurface(),
+                    mPendingDestroySurface.mSurfaceControl).apply();
             }
             destroySurfaceLocked();
             mSurfaceDestroyDeferred = true;
@@ -413,9 +414,9 @@
                 // child layers need to be reparented to the new surface to make this
                 // transparent to the app.
                 if (mWin.mActivityRecord == null || mWin.mActivityRecord.isRelaunching() == false) {
-                    mPostDrawTransaction.reparentChildren(mPendingDestroySurface.mSurfaceControl,
-                            mSurfaceController.mSurfaceControl)
-                            .apply();
+                    mPostDrawTransaction.reparentChildren(
+                        mPendingDestroySurface.getClientViewRootSurface(),
+                        mSurfaceController.mSurfaceControl).apply();
                 }
             }
         }
@@ -875,7 +876,7 @@
 
         if (mSurfaceResized && (mAttrType == TYPE_BASE_APPLICATION) &&
             (task != null) && (task.getMainWindowSizeChangeTransaction() != null)) {
-            mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+            mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
                     mWin.getFrameNumber());
             SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
             task.setMainWindowSizeChangeTransaction(null);
@@ -1012,7 +1013,7 @@
                         // the WS position is reset (so the stack position is shown) at the same
                         // time that the buffer size changes.
                         setOffsetPositionForStackResize(false);
-                        mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+                        mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
                                 mWin.getFrameNumber());
                     } else {
                         final ActivityStack stack = mWin.getRootTask();
@@ -1043,7 +1044,7 @@
         // comes in at the new size (normally position and crop are unfrozen).
         // deferTransactionUntil accomplishes this for us.
         if (wasForceScaled && !mForceScaleUntilResize) {
-            mSurfaceController.deferTransactionUntil(mWin.getDeferTransactionBarrier(),
+            mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
                     mWin.getFrameNumber());
             mSurfaceController.forceScaleableInTransaction(false);
         }
@@ -1288,8 +1289,9 @@
         if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
             final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
             mPostDrawTransaction.reparent(pendingSurfaceControl, null);
-            mPostDrawTransaction.reparentChildren(pendingSurfaceControl,
-                    mSurfaceController.mSurfaceControl);
+            mPostDrawTransaction.reparentChildren(
+                mPendingDestroySurface.getClientViewRootSurface(),
+                mSurfaceController.mSurfaceControl);
         }
 
         SurfaceControl.mergeToGlobalTransaction(mPostDrawTransaction);
@@ -1521,10 +1523,10 @@
         mOffsetPositionForStackResize = offsetPositionForStackResize;
     }
 
-    SurfaceControl getDeferTransactionBarrier() {
+    SurfaceControl getClientViewRootSurface() {
         if (!hasSurface()) {
             return null;
         }
-        return mSurfaceController.getDeferTransactionBarrier();
+        return mSurfaceController.getClientViewRootSurface();
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 383c0d9..d7c97b9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -533,7 +533,15 @@
         return mSurfaceH;
     }
 
-    SurfaceControl getDeferTransactionBarrier() {
+    /**
+     * Returns the Surface which the client-framework ViewRootImpl will be using.
+     * This is either the WSA SurfaceControl or it's BLAST child surface.
+     * This has too main uses:
+     * 1. This is the Surface the client will add children to, we use this to make
+     *    sure we don't reparent the BLAST surface itself when calling reparentChildren
+     * 2. We use this as the barrier Surface for some deferTransaction operations.
+     */
+    SurfaceControl getClientViewRootSurface() {
         if (mBLASTSurfaceControl != null) {
             return mBLASTSurfaceControl;
         }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 98d9c8fc..b7c6af2 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -28,13 +28,13 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowContainerChildProto.WINDOW_TOKEN;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
 import static com.android.server.wm.WindowTokenProto.HASH_CODE;
 import static com.android.server.wm.WindowTokenProto.PAUSED;
 import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW;
-import static com.android.server.wm.WindowTokenProto.WINDOWS;
 import static com.android.server.wm.WindowTokenProto.WINDOW_CONTAINER;
 
 import android.annotation.CallSuper;
@@ -50,6 +50,7 @@
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 
@@ -99,7 +100,8 @@
     private Configuration mLastReportedConfig;
     private int mLastReportedDisplay = INVALID_DISPLAY;
 
-    private final boolean mFromClientToken;
+    @VisibleForTesting
+    final boolean mFromClientToken;
 
     /**
      * Used to fix the transform of the token to be rotated to a rotation different than it's
@@ -180,13 +182,13 @@
     WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
             DisplayContent dc, boolean ownerCanManageAppTokens) {
         this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
-                false /* roundedCornersOverlay */);
+                false /* roundedCornerOverlay */);
     }
 
     WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
-            DisplayContent dc, boolean ownerCanManageAppTokens, boolean fromClientToken) {
+            DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
         this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
-                false /* roundedCornersOverlay */, fromClientToken);
+                roundedCornerOverlay, false /* fromClientToken */);
     }
 
     WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
@@ -539,15 +541,16 @@
         final long token = proto.start(fieldId);
         super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
         proto.write(HASH_CODE, System.identityHashCode(this));
-        for (int i = 0; i < mChildren.size(); i++) {
-            final WindowState w = mChildren.get(i);
-            w.dumpDebug(proto, WINDOWS, logLevel);
-        }
         proto.write(WAITING_TO_SHOW, waitingToShow);
         proto.write(PAUSED, paused);
         proto.end(token);
     }
 
+    @Override
+    long getProtoFieldId() {
+        return WINDOW_TOKEN;
+    }
+
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
         super.dump(pw, prefix, dumpAll);
         pw.print(prefix); pw.print("windows="); pw.println(mChildren);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c58eae1..312d2d2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -148,10 +148,6 @@
 import android.app.admin.SystemUpdateInfo;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
-import android.app.timedetector.ManualTimeSuggestion;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneDetector;
 import android.app.trust.TrustManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.compat.annotation.ChangeId;
@@ -2118,14 +2114,6 @@
             return mContext.getSystemService(AlarmManager.class);
         }
 
-        TimeDetector getTimeDetector() {
-            return mContext.getSystemService(TimeDetector.class);
-        }
-
-        TimeZoneDetector getTimeZoneDetector() {
-            return mContext.getSystemService(TimeZoneDetector.class);
-        }
-
         ConnectivityManager getConnectivityManager() {
             return mContext.getSystemService(ConnectivityManager.class);
         }
@@ -11730,15 +11718,11 @@
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
             return false;
         }
-        ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
-                millis, "DevicePolicyManagerService: setTime");
-        mInjector.binderWithCleanCallingIdentity(
-                () -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
-
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_TIME)
                 .setAdmin(who)
                 .write();
+        mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
         return true;
     }
 
@@ -11750,11 +11734,8 @@
         if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME_ZONE, 0) == 1) {
             return false;
         }
-        ManualTimeZoneSuggestion manualTimeZoneSuggestion =
-                TimeZoneDetector.createManualTimeZoneSuggestion(
-                        timeZone, "DevicePolicyManagerService: setTimeZone");
         mInjector.binderWithCleanCallingIdentity(() ->
-                mInjector.getTimeZoneDetector().suggestManualTimeZone(manualTimeZoneSuggestion));
+                mInjector.getAlarmManager().setTimeZone(timeZone));
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_TIME_ZONE)
diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h
index 4075da6..28613e1 100644
--- a/services/incremental/BinderIncrementalService.h
+++ b/services/incremental/BinderIncrementalService.h
@@ -31,7 +31,7 @@
     BinderIncrementalService(const sp<IServiceManager>& sm);
 
     static BinderIncrementalService* start();
-    static const char16_t* getServiceName() { return u"incremental_service"; }
+    static const char16_t* getServiceName() { return u"incremental"; }
     status_t dump(int fd, const Vector<String16>& args) final;
 
     void onSystemReady();
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 8481e5b..28e3d4b 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -89,25 +89,21 @@
      * Loads conversations from disk to memory in a background thread. This should be called
      * after the device powers on and the user has been unlocked.
      */
-    @MainThread
-    void loadConversationsFromDisk() {
-        mScheduledExecutorService.execute(() -> {
-            synchronized (this) {
-                ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
-                        getConversationInfosProtoDiskReadWriter();
-                if (conversationInfosProtoDiskReadWriter == null) {
-                    return;
-                }
-                List<ConversationInfo> conversationsOnDisk =
-                        conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
-                if (conversationsOnDisk == null) {
-                    return;
-                }
-                for (ConversationInfo conversationInfo : conversationsOnDisk) {
-                    updateConversationsInMemory(conversationInfo);
-                }
-            }
-        });
+    @WorkerThread
+    synchronized void loadConversationsFromDisk() {
+        ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
+                getConversationInfosProtoDiskReadWriter();
+        if (conversationInfosProtoDiskReadWriter == null) {
+            return;
+        }
+        List<ConversationInfo> conversationsOnDisk =
+                conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
+        if (conversationsOnDisk == null) {
+            return;
+        }
+        for (ConversationInfo conversationInfo : conversationsOnDisk) {
+            updateConversationsInMemory(conversationInfo);
+        }
     }
 
     /**
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 4e0afc5..7085f96 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -28,6 +28,7 @@
 import android.app.prediction.AppTargetEvent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -87,13 +88,13 @@
 
     private static final String TAG = "DataManager";
 
-    private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
+    private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
     private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
 
     private final Context mContext;
     private final Injector mInjector;
-    private final ScheduledExecutorService mUsageStatsQueryExecutor;
-    private final ScheduledExecutorService mDiskReadWriterExecutor;
+    private final ScheduledExecutorService mScheduledExecutor;
+    private final Object mLock = new Object();
 
     private final SparseArray<UserData> mUserDataArray = new SparseArray<>();
     private final SparseArray<BroadcastReceiver> mBroadcastReceivers = new SparseArray<>();
@@ -118,8 +119,7 @@
     DataManager(Context context, Injector injector) {
         mContext = context;
         mInjector = injector;
-        mUsageStatsQueryExecutor = mInjector.createScheduledExecutor();
-        mDiskReadWriterExecutor = mInjector.createScheduledExecutor();
+        mScheduledExecutor = mInjector.createScheduledExecutor();
     }
 
     /** Initialization. Called when the system services are up running. */
@@ -138,103 +138,56 @@
 
     /** This method is called when a user is unlocked. */
     public void onUserUnlocked(int userId) {
-        UserData userData = mUserDataArray.get(userId);
-        if (userData == null) {
-            userData = new UserData(userId, mDiskReadWriterExecutor);
-            mUserDataArray.put(userId, userData);
+        synchronized (mLock) {
+            UserData userData = mUserDataArray.get(userId);
+            if (userData == null) {
+                userData = new UserData(userId, mScheduledExecutor);
+                mUserDataArray.put(userId, userData);
+            }
+            userData.setUserUnlocked();
         }
-        userData.setUserUnlocked();
-        updateDefaultDialer(userData);
-        updateDefaultSmsApp(userData);
-
-        ScheduledFuture<?> scheduledFuture = mUsageStatsQueryExecutor.scheduleAtFixedRate(
-                new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
-                TimeUnit.SECONDS);
-        mUsageStatsQueryFutures.put(userId, scheduledFuture);
-
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
-        intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
-        BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
-        mBroadcastReceivers.put(userId, broadcastReceiver);
-        mContext.registerReceiverAsUser(
-                broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
-
-        ContentObserver contactsContentObserver = new ContactsContentObserver(
-                BackgroundThread.getHandler());
-        mContactsContentObservers.put(userId, contactsContentObserver);
-        mContext.getContentResolver().registerContentObserver(
-                Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
-                contactsContentObserver, userId);
-
-        NotificationListener notificationListener = new NotificationListener();
-        mNotificationListeners.put(userId, notificationListener);
-        try {
-            notificationListener.registerAsSystemService(mContext,
-                    new ComponentName(mContext, getClass()), userId);
-        } catch (RemoteException e) {
-            // Should never occur for local calls.
-        }
-
-        PackageMonitor packageMonitor = new PerUserPackageMonitor();
-        packageMonitor.register(mContext, null, UserHandle.of(userId), true);
-        mPackageMonitors.put(userId, packageMonitor);
-
-        if (userId == UserHandle.USER_SYSTEM) {
-            // The call log and MMS/SMS messages are shared across user profiles. So only need to
-            // register the content observers once for the primary user.
-            // TODO: Register observers after the conversations and events being loaded from disk.
-            mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
-            mContext.getContentResolver().registerContentObserver(
-                    CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
-                    mCallLogContentObserver, UserHandle.USER_SYSTEM);
-
-            mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
-            mContext.getContentResolver().registerContentObserver(
-                    MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
-                    mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
-        }
-
-        DataMaintenanceService.scheduleJob(mContext, userId);
+        mScheduledExecutor.execute(() -> setupUser(userId));
     }
 
     /** This method is called when a user is stopping. */
     public void onUserStopping(int userId) {
-        if (mUserDataArray.indexOfKey(userId) >= 0) {
-            mUserDataArray.get(userId).setUserStopped();
-        }
-        if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
-            mUsageStatsQueryFutures.get(userId).cancel(true);
-        }
-        if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
-            mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
-        }
-        if (mContactsContentObservers.indexOfKey(userId) >= 0) {
-            mContext.getContentResolver().unregisterContentObserver(
-                    mContactsContentObservers.get(userId));
-        }
-        if (mNotificationListeners.indexOfKey(userId) >= 0) {
-            try {
-                mNotificationListeners.get(userId).unregisterAsSystemService();
-            } catch (RemoteException e) {
-                // Should never occur for local calls.
+        synchronized (mLock) {
+            ContentResolver contentResolver = mContext.getContentResolver();
+            if (mUserDataArray.indexOfKey(userId) >= 0) {
+                mUserDataArray.get(userId).setUserStopped();
             }
-        }
-        if (mPackageMonitors.indexOfKey(userId) >= 0) {
-            mPackageMonitors.get(userId).unregister();
-        }
-        if (userId == UserHandle.USER_SYSTEM) {
-            if (mCallLogContentObserver != null) {
-                mContext.getContentResolver().unregisterContentObserver(mCallLogContentObserver);
-                mCallLogContentObserver = null;
+            if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
+                mUsageStatsQueryFutures.get(userId).cancel(true);
             }
-            if (mMmsSmsContentObserver != null) {
-                mContext.getContentResolver().unregisterContentObserver(mMmsSmsContentObserver);
-                mCallLogContentObserver = null;
+            if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
+                mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
             }
-        }
+            if (mContactsContentObservers.indexOfKey(userId) >= 0) {
+                contentResolver.unregisterContentObserver(mContactsContentObservers.get(userId));
+            }
+            if (mNotificationListeners.indexOfKey(userId) >= 0) {
+                try {
+                    mNotificationListeners.get(userId).unregisterAsSystemService();
+                } catch (RemoteException e) {
+                    // Should never occur for local calls.
+                }
+            }
+            if (mPackageMonitors.indexOfKey(userId) >= 0) {
+                mPackageMonitors.get(userId).unregister();
+            }
+            if (userId == UserHandle.USER_SYSTEM) {
+                if (mCallLogContentObserver != null) {
+                    contentResolver.unregisterContentObserver(mCallLogContentObserver);
+                    mCallLogContentObserver = null;
+                }
+                if (mMmsSmsContentObserver != null) {
+                    contentResolver.unregisterContentObserver(mMmsSmsContentObserver);
+                    mCallLogContentObserver = null;
+                }
+            }
 
-        DataMaintenanceService.cancelJob(mContext, userId);
+            DataMaintenanceService.cancelJob(mContext, userId);
+        }
     }
 
     /**
@@ -288,6 +241,9 @@
             return;
         }
         UserData userData = getUnlockedUserData(appTarget.getUser().getIdentifier());
+        if (userData == null) {
+            return;
+        }
         PackageData packageData = userData.getOrCreatePackageData(appTarget.getPackageName());
         String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
         @Event.EventType int eventType = mimeTypeToShareEventType(mimeType);
@@ -353,6 +309,68 @@
         userData.restore(payload);
     }
 
+    private void setupUser(@UserIdInt int userId) {
+        synchronized (mLock) {
+            UserData userData = getUnlockedUserData(userId);
+            if (userData == null) {
+                return;
+            }
+            userData.loadUserData();
+
+            updateDefaultDialer(userData);
+            updateDefaultSmsApp(userData);
+
+            ScheduledFuture<?> scheduledFuture = mScheduledExecutor.scheduleAtFixedRate(
+                    new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
+                    TimeUnit.SECONDS);
+            mUsageStatsQueryFutures.put(userId, scheduledFuture);
+
+            IntentFilter intentFilter = new IntentFilter();
+            intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
+            intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+            BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
+            mBroadcastReceivers.put(userId, broadcastReceiver);
+            mContext.registerReceiverAsUser(
+                    broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
+
+            ContentObserver contactsContentObserver = new ContactsContentObserver(
+                    BackgroundThread.getHandler());
+            mContactsContentObservers.put(userId, contactsContentObserver);
+            mContext.getContentResolver().registerContentObserver(
+                    Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
+                    contactsContentObserver, userId);
+
+            NotificationListener notificationListener = new NotificationListener();
+            mNotificationListeners.put(userId, notificationListener);
+            try {
+                notificationListener.registerAsSystemService(mContext,
+                        new ComponentName(mContext, getClass()), userId);
+            } catch (RemoteException e) {
+                // Should never occur for local calls.
+            }
+
+            PackageMonitor packageMonitor = new PerUserPackageMonitor();
+            packageMonitor.register(mContext, null, UserHandle.of(userId), true);
+            mPackageMonitors.put(userId, packageMonitor);
+
+            if (userId == UserHandle.USER_SYSTEM) {
+                // The call log and MMS/SMS messages are shared across user profiles. So only need
+                // to register the content observers once for the primary user.
+                mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
+                mContext.getContentResolver().registerContentObserver(
+                        CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
+                        mCallLogContentObserver, UserHandle.USER_SYSTEM);
+
+                mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
+                mContext.getContentResolver().registerContentObserver(
+                        MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
+                        mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
+            }
+
+            DataMaintenanceService.scheduleJob(mContext, userId);
+        }
+    }
+
     private int mimeTypeToShareEventType(String mimeType) {
         if (mimeType.startsWith("text/")) {
             return Event.TYPE_SHARE_TEXT;
diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java
index 00d4241..9cf84c9 100644
--- a/services/people/java/com/android/server/people/data/EventStore.java
+++ b/services/people/java/com/android/server/people/data/EventStore.java
@@ -17,9 +17,9 @@
 package com.android.server.people.data;
 
 import android.annotation.IntDef;
-import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.WorkerThread;
 import android.net.Uri;
 import android.util.ArrayMap;
 
@@ -90,20 +90,16 @@
      * Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers
      * on and user is unlocked.
      */
-    @MainThread
-    void loadFromDisk() {
-        mScheduledExecutorService.execute(() -> {
-            synchronized (this) {
-                for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
-                        category++) {
-                    File categoryDir = mEventsCategoryDirs.get(category);
-                    Map<String, EventHistoryImpl> existingEventHistoriesImpl =
-                            EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
-                                    mScheduledExecutorService);
-                    mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
-                }
-            }
-        });
+    @WorkerThread
+    synchronized void loadFromDisk() {
+        for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
+                category++) {
+            File categoryDir = mEventsCategoryDirs.get(category);
+            Map<String, EventHistoryImpl> existingEventHistoriesImpl =
+                    EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
+                            mScheduledExecutorService);
+            mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
+        }
     }
 
     /**
diff --git a/services/people/java/com/android/server/people/data/MmsQueryHelper.java b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
index 1e485c0..39dba9c 100644
--- a/services/people/java/com/android/server/people/data/MmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.Binder;
 import android.provider.Telephony.BaseMmsColumns;
 import android.provider.Telephony.Mms;
 import android.telephony.PhoneNumberUtils;
@@ -71,31 +72,36 @@
         // NOTE: The field Mms.DATE is stored in seconds, not milliseconds.
         String[] selectionArgs = new String[] { Long.toString(sinceTime / MILLIS_PER_SECONDS) };
         boolean hasResults = false;
-        try (Cursor cursor = mContext.getContentResolver().query(
-                Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
-            if (cursor == null) {
-                Slog.w(TAG, "Cursor is null when querying MMS table.");
-                return false;
-            }
-            while (cursor.moveToNext()) {
-                // ID
-                int msgIdIndex = cursor.getColumnIndex(Mms._ID);
-                String msgId = cursor.getString(msgIdIndex);
+        Binder.allowBlockingForCurrentThread();
+        try {
+            try (Cursor cursor = mContext.getContentResolver().query(
+                    Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+                if (cursor == null) {
+                    Slog.w(TAG, "Cursor is null when querying MMS table.");
+                    return false;
+                }
+                while (cursor.moveToNext()) {
+                    // ID
+                    int msgIdIndex = cursor.getColumnIndex(Mms._ID);
+                    String msgId = cursor.getString(msgIdIndex);
 
-                // Date
-                int dateIndex = cursor.getColumnIndex(Mms.DATE);
-                long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
+                    // Date
+                    int dateIndex = cursor.getColumnIndex(Mms.DATE);
+                    long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
 
-                // Message box
-                int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
-                int msgBox = cursor.getInt(msgBoxIndex);
+                    // Message box
+                    int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
+                    int msgBox = cursor.getInt(msgBoxIndex);
 
-                mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
-                String address = getMmsAddress(msgId, msgBox);
-                if (address != null && addEvent(address, date, msgBox)) {
-                    hasResults = true;
+                    mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+                    String address = getMmsAddress(msgId, msgBox);
+                    if (address != null && addEvent(address, date, msgBox)) {
+                        hasResults = true;
+                    }
                 }
             }
+        } finally {
+            Binder.defaultBlockingForCurrentThread();
         }
         return hasResults;
     }
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index 3e4c992..28837d5 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -25,6 +25,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
 import android.content.LocusId;
 import android.os.FileUtils;
 import android.text.TextUtils;
@@ -77,6 +78,7 @@
      * Returns a map of package directory names as keys and their associated {@link PackageData}.
      * This should be called when device is powered on and unlocked.
      */
+    @WorkerThread
     @NonNull
     static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId,
             @NonNull Predicate<String> isDefaultDialerPredicate,
diff --git a/services/people/java/com/android/server/people/data/SmsQueryHelper.java b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
index c38c846..a5eb3a5 100644
--- a/services/people/java/com/android/server/people/data/SmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
@@ -19,6 +19,7 @@
 import android.annotation.WorkerThread;
 import android.content.Context;
 import android.database.Cursor;
+import android.os.Binder;
 import android.provider.Telephony.Sms;
 import android.provider.Telephony.TextBasedSmsColumns;
 import android.telephony.PhoneNumberUtils;
@@ -65,35 +66,40 @@
         String selection = Sms.DATE + " > ?";
         String[] selectionArgs = new String[] { Long.toString(sinceTime) };
         boolean hasResults = false;
-        try (Cursor cursor = mContext.getContentResolver().query(
-                Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
-            if (cursor == null) {
-                Slog.w(TAG, "Cursor is null when querying SMS table.");
-                return false;
-            }
-            while (cursor.moveToNext()) {
-                // ID
-                int msgIdIndex = cursor.getColumnIndex(Sms._ID);
-                String msgId = cursor.getString(msgIdIndex);
+        Binder.allowBlockingForCurrentThread();
+        try {
+            try (Cursor cursor = mContext.getContentResolver().query(
+                    Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+                if (cursor == null) {
+                    Slog.w(TAG, "Cursor is null when querying SMS table.");
+                    return false;
+                }
+                while (cursor.moveToNext()) {
+                    // ID
+                    int msgIdIndex = cursor.getColumnIndex(Sms._ID);
+                    String msgId = cursor.getString(msgIdIndex);
 
-                // Date
-                int dateIndex = cursor.getColumnIndex(Sms.DATE);
-                long date = cursor.getLong(dateIndex);
+                    // Date
+                    int dateIndex = cursor.getColumnIndex(Sms.DATE);
+                    long date = cursor.getLong(dateIndex);
 
-                // Type
-                int typeIndex = cursor.getColumnIndex(Sms.TYPE);
-                int type = cursor.getInt(typeIndex);
+                    // Type
+                    int typeIndex = cursor.getColumnIndex(Sms.TYPE);
+                    int type = cursor.getInt(typeIndex);
 
-                // Address
-                int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
-                String address = PhoneNumberUtils.formatNumberToE164(
-                        cursor.getString(addressIndex), mCurrentCountryIso);
+                    // Address
+                    int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
+                    String address = PhoneNumberUtils.formatNumberToE164(
+                            cursor.getString(addressIndex), mCurrentCountryIso);
 
-                mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
-                if (address != null && addEvent(address, date, type)) {
-                    hasResults = true;
+                    mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+                    if (address != null && addEvent(address, date, type)) {
+                        hasResults = true;
+                    }
                 }
             }
+        } finally {
+            Binder.defaultBlockingForCurrentThread();
         }
         return hasResults;
     }
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index ed8c595..429d5b7 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
 import android.os.Environment;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -75,12 +76,6 @@
 
     void setUserUnlocked() {
         mIsUnlocked = true;
-
-        // Ensures per user root directory for people data is present, and attempt to load
-        // data from disk.
-        mPerUserPeopleDataDir.mkdirs();
-        mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
-                this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir));
     }
 
     void setUserStopped() {
@@ -91,6 +86,15 @@
         return mIsUnlocked;
     }
 
+    @WorkerThread
+    void loadUserData() {
+        mPerUserPeopleDataDir.mkdir();
+        Map<String, PackageData> packageDataMap = PackageData.packagesDataFromDisk(
+                mUserId, this::isDefaultDialer, this::isDefaultSmsApp, mScheduledExecutorService,
+                mPerUserPeopleDataDir);
+        mPackageDataMap.putAll(packageDataMap);
+    }
+
     /**
      * Gets the {@link PackageData} for the specified {@code packageName} if exists; otherwise
      * creates a new instance and returns it.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 6083ce34..95f4e83 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -847,8 +847,8 @@
         app.connectionGroup = connectionGroup;
         app.setProcState = procState;
         app.lastMemInfo = spy(new Debug.MemoryInfo());
-        doReturn((int) pss).when(app.lastMemInfo).getTotalPss();
-        doReturn((int) rss).when(app.lastMemInfo).getTotalRss();
+        app.lastPss = pss;
+        app.mLastRss = rss;
         return app;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 4722b39..e5ec1f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -36,6 +36,7 @@
 import com.android.server.testables.TestableDeviceConfig;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -267,9 +268,7 @@
 
     @Test
     public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException {
-        if (!mCachedAppOptimizerUnderTest.isFreezerSupported()) {
-            return;
-        }
+        Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
 
         assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
                 CachedAppOptimizer.DEFAULT_USE_FREEZER);
diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
index 16291b2..425c724 100644
--- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java
@@ -176,7 +176,8 @@
         CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext)
                         .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1)
                         .addTargetSdkChangeWithId(TARGET_SDK, 2)
-                        .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build();
+                        .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3)
+                        .addDisabledChangeWithId(4).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
@@ -190,6 +191,8 @@
                 overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME);
         OverrideAllowedState stateTargetSdkAfterChange =
                 overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME);
+        OverrideAllowedState stateDisabledChange =
+                overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME);
 
         assertThat(stateTargetSdkLessChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE));
@@ -197,6 +200,8 @@
                 .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK));
         assertThat(stateTargetSdkAfterChange)
                 .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER));
+        assertThat(stateDisabledChange)
+                .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, -1));
     }
 
     @Test
@@ -343,21 +348,22 @@
     }
 
     @Test
-    public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride()
+    public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_allowOverride()
             throws Exception {
         CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext)
-                        .addDisabledChangeWithId(1).build();
+                .addDisabledChangeWithId(1).build();
         IOverrideValidator overrideValidator = config.getOverrideValidator();
         when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
                 .thenReturn(ApplicationInfoBuilder.create()
                         .withPackageName(PACKAGE_NAME)
+                        .withTargetSdk(TARGET_SDK)
                         .debuggable().build());
 
         OverrideAllowedState allowedState =
                 overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME);
 
         assertThat(allowedState)
-                .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1));
+                .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, -1));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 5ad81b2..c1bcf1f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,8 +22,6 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.backup.IBackupManager;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.TimeZoneDetector;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.Context;
 import android.content.Intent;
@@ -236,16 +234,6 @@
         AlarmManager getAlarmManager() {return services.alarmManager;}
 
         @Override
-        TimeDetector getTimeDetector() {
-            return services.timeDetector;
-        }
-
-        @Override
-        TimeZoneDetector getTimeZoneDetector() {
-            return services.timeZoneDetector;
-        }
-
-        @Override
         LockPatternUtils newLockPatternUtils() {
             return services.lockPatternUtils;
         }
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 ac818ea..2a6a24e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -67,9 +67,6 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.FactoryResetProtectionPolicy;
 import android.app.admin.PasswordMetrics;
-import android.app.timedetector.ManualTimeSuggestion;
-import android.app.timezonedetector.ManualTimeZoneSuggestion;
-import android.app.timezonedetector.TimeZoneDetector;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -3969,19 +3966,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         dpm.setTime(admin1, 0);
-
-        BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
-            @Override
-            public boolean matches(Object item) {
-                final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
-                return suggestion.getUtcTime().getValue() == 0;
-            }
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("ManualTimeSuggestion{utcTime.value=0}");
-            }
-        };
-        verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
+        verify(getServices().alarmManager).setTime(0);
     }
 
     public void testSetTimeFailWithPO() throws Exception {
@@ -3993,19 +3978,7 @@
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
         dpm.setTime(admin1, 0);
-
-        BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
-            @Override
-            public boolean matches(Object item) {
-                final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
-                return suggestion.getUtcTime().getValue() == 0;
-            }
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("ManualTimeSuggestion{utcTime.value=0}");
-            }
-        };
-        verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
+        verify(getServices().alarmManager).setTime(0);
     }
 
     public void testSetTimeWithAutoTimeOn() throws Exception {
@@ -4020,9 +3993,7 @@
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         dpm.setTimeZone(admin1, "Asia/Shanghai");
-        ManualTimeZoneSuggestion suggestion =
-                TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
-        verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
+        verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
     }
 
     public void testSetTimeZoneFailWithPO() throws Exception {
@@ -4035,9 +4006,7 @@
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
         dpm.setTimeZone(admin1, "Asia/Shanghai");
-        ManualTimeZoneSuggestion suggestion =
-                TimeZoneDetector.createManualTimeZoneSuggestion("Asia/Shanghai", "Test debug info");
-        verify(getServices().timeZoneDetector).suggestManualTimeZone(suggestion);
+        verify(getServices().alarmManager).setTimeZone("Asia/Shanghai");
     }
 
     public void testSetTimeZoneWithAutoTimeZoneOn() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 12228c1..8625a1e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -207,8 +207,6 @@
         switch (name) {
             case Context.ALARM_SERVICE:
                 return mMockSystemServices.alarmManager;
-            case Context.TIME_DETECTOR_SERVICE:
-                return mMockSystemServices.timeDetector;
             case Context.USER_SERVICE:
                 return mMockSystemServices.userManager;
             case Context.POWER_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 01f1a3e..bbd4472 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -33,8 +33,6 @@
 import android.app.IActivityTaskManager;
 import android.app.NotificationManager;
 import android.app.backup.IBackupManager;
-import android.app.timedetector.TimeDetector;
-import android.app.timezonedetector.TimeZoneDetector;
 import android.app.usage.UsageStatsManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -118,8 +116,6 @@
     public final TelephonyManager telephonyManager;
     public final AccountManager accountManager;
     public final AlarmManager alarmManager;
-    public final TimeDetector timeDetector;
-    public final TimeZoneDetector timeZoneDetector;
     public final KeyChain.KeyChainConnection keyChainConnection;
     public final CrossProfileApps crossProfileApps;
     public final PersistentDataBlockManagerInternal persistentDataBlockManagerInternal;
@@ -164,8 +160,6 @@
         telephonyManager = mock(TelephonyManager.class);
         accountManager = mock(AccountManager.class);
         alarmManager = mock(AlarmManager.class);
-        timeDetector = mock(TimeDetector.class);
-        timeZoneDetector = mock(TimeZoneDetector.class);
         keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
         crossProfileApps = mock(CrossProfileApps.class);
         persistentDataBlockManagerInternal = mock(PersistentDataBlockManagerInternal.class);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index e2b63e2..3dd1504 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -62,7 +62,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.provider.Settings;
-import android.security.FileIntegrityManager;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -136,7 +135,6 @@
     @Mock RuleEvaluationEngine mRuleEvaluationEngine;
     @Mock IntegrityFileManager mIntegrityFileManager;
     @Mock Handler mHandler;
-    FileIntegrityManager mFileIntegrityManager;
 
     private final Context mRealContext = InstrumentationRegistry.getTargetContext();
 
@@ -165,16 +163,12 @@
             Files.copy(inputStream, mTestApkSourceStamp.toPath(), REPLACE_EXISTING);
         }
 
-        mFileIntegrityManager =
-                (FileIntegrityManager)
-                        mRealContext.getSystemService(Context.FILE_INTEGRITY_SERVICE);
         mService =
                 new AppIntegrityManagerServiceImpl(
                         mMockContext,
                         mPackageManagerInternal,
                         mRuleEvaluationEngine,
                         mIntegrityFileManager,
-                        mFileIntegrityManager,
                         mHandler);
 
         mSpyPackageManager = spy(mRealContext.getPackageManager());
@@ -379,7 +373,7 @@
         AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
         assertTrue(appInstallMetadata.isStampPresent());
         assertTrue(appInstallMetadata.isStampVerified());
-        assertFalse(appInstallMetadata.isStampTrusted());
+        assertTrue(appInstallMetadata.isStampTrusted());
         assertEquals(SOURCE_STAMP_CERTIFICATE_HASH, appInstallMetadata.getStampCertificateHash());
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
index b0def60..ccbaee4 100644
--- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -18,6 +18,11 @@
 
 import static android.hardware.lights.LightsRequest.Builder;
 
+import static android.graphics.Color.BLACK;
+import static android.graphics.Color.BLUE;
+import static android.graphics.Color.GREEN;
+import static android.graphics.Color.WHITE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
@@ -92,7 +97,7 @@
 
         // When the session requests to turn 3/4 lights on:
         LightsManager.LightsSession session = manager.openSession();
-        session.setLights(new Builder()
+        session.requestLights(new Builder()
                 .setLight(manager.getLights().get(0), new LightState(0xf1))
                 .setLight(manager.getLights().get(1), new LightState(0xf2))
                 .setLight(manager.getLights().get(2), new LightState(0xf3))
@@ -114,18 +119,18 @@
         Light micLight = manager.getLights().get(0);
 
         // The light should begin by being off.
-        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
 
         // When a session commits changes:
         LightsManager.LightsSession session = manager.openSession();
-        session.setLights(new Builder().setLight(micLight, new LightState(0xff00ff00)).build());
+        session.requestLights(new Builder().setLight(micLight, new LightState(GREEN)).build());
         // Then the light should turn on.
-        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff00ff00);
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(GREEN);
 
         // When the session goes away:
         session.close();
         // Then the light should turn off.
-        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
     }
 
     @Test
@@ -138,15 +143,15 @@
         LightsManager.LightsSession session2 = manager.openSession();
 
         // When session1 and session2 both request the same light:
-        session1.setLights(new Builder().setLight(micLight, new LightState(0xff0000ff)).build());
-        session2.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+        session1.requestLights(new Builder().setLight(micLight, new LightState(BLUE)).build());
+        session2.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
         // Then session1 should win because it was created first.
-        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff0000ff);
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE);
 
         // When session1 goes away:
         session1.close();
         // Then session2 should have its request go into effect.
-        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xffffffff);
+        assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE);
 
         // When session2 goes away:
         session2.close();
@@ -162,10 +167,10 @@
 
         // When the session turns a light on:
         LightsManager.LightsSession session = manager.openSession();
-        session.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+        session.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
 
         // And then the session clears it again:
-        session.setLights(new Builder().clearLight(micLight).build());
+        session.requestLights(new Builder().clearLight(micLight).build());
 
         // Then the light should turn back off.
         assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index 4e63237..e10cbbf 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -273,9 +273,8 @@
         // Ensure that futures were cancelled and the immediate flush occurred.
         assertEquals(0, mMockScheduledExecutorService.getFutures().size());
 
-        // Expect to see 2 executes: loadConversationFromDisk and saveConversationsToDisk.
-        // loadConversationFromDisk gets called each time we call #resetConversationStore().
-        assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
+        // Expect to see 1 execute: saveConversationsToDisk.
+        assertEquals(1, mMockScheduledExecutorService.getExecutes().size());
 
         resetConversationStore();
         ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index a4d63ac..5199604 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -183,6 +183,11 @@
 
         when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(
                 TimeUnit.class))).thenReturn(mScheduledFuture);
+        doAnswer(ans -> {
+            Runnable runnable = (Runnable) ans.getArguments()[0];
+            runnable.run();
+            return null;
+        }).when(mExecutorService).execute(any(Runnable.class));
 
         when(mUserManager.getEnabledProfiles(USER_ID_PRIMARY))
                 .thenReturn(Arrays.asList(
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 049c8e1..1c267a0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.app.ActivityManager.START_ABORTED;
+import static android.app.ActivityManager.START_CANCELED;
 import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
 import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
 import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -892,7 +893,7 @@
                 .execute();
 
         // Simulate a failed start
-        starter.postStartActivityProcessing(null, START_ABORTED, null);
+        starter.postStartActivityProcessing(null, START_CANCELED, null);
 
         verify(recentTasks, times(1)).setFreezeTaskListReordering();
         verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
@@ -1019,7 +1020,7 @@
         public void taskAppeared(ActivityManager.RunningTaskInfo info) {
         }
         @Override
-        public void taskVanished(IWindowContainer wc) {
+        public void taskVanished(ActivityManager.RunningTaskInfo info) {
         }
         @Override
         public void transactionReady(int id, SurfaceControl.Transaction t) {
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 1796d85..4634e2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -234,6 +234,10 @@
                 mTask = new TaskBuilder(mService.mStackSupervisor)
                         .setComponent(mComponent)
                         .setStack(mStack).build();
+            } else if (mTask == null && mStack != null && DisplayContent.alwaysCreateStack(
+                    mStack.getWindowingMode(), mStack.getActivityType())) {
+                // The stack can be the task root.
+                mTask = mStack;
             }
 
             Intent intent = new Intent();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index c7f94ef..34ac835 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -98,7 +98,7 @@
         mDisplayContent.mOpeningApps.add(win.mActivityRecord);
         try {
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                    new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                    new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo();
@@ -136,7 +136,7 @@
     public void testCancel() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         mController.goodToGo();
@@ -150,7 +150,7 @@
     public void testTimeout() throws Exception {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         mController.goodToGo();
@@ -170,7 +170,8 @@
             final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
                     "testWin");
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
-                    win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                    win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
+                    null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo();
@@ -201,7 +202,7 @@
     public void testNotReallyStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         mController.createRemoteAnimationRecord(win.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null);
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null);
         mController.goodToGo();
         verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
@@ -211,9 +212,9 @@
         final WindowState win1 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin1");
         final WindowState win2 = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin2");
         mController.createRemoteAnimationRecord(win1.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null);
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null);
         final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win2.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         mController.goodToGo();
@@ -234,7 +235,7 @@
     public void testRemovedBeforeStarted() {
         final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
         final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
         adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                 mFinishedCallback);
         win.mActivityRecord.removeImmediately();
@@ -250,7 +251,7 @@
         mDisplayContent.mChangingContainers.add(win.mActivityRecord);
         try {
             final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
-                    win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150),
+                    win.mActivityRecord, new Point(50, 100), null, new Rect(50, 100, 150, 150),
                     new Rect(0, 0, 200, 200));
             assertNotNull(record.mThumbnailAdapter);
             ((AnimationAdapter) record.mAdapter)
@@ -304,7 +305,7 @@
         mDisplayContent.mOpeningApps.add(win.mActivityRecord);
         try {
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                    new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                    new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo();
@@ -333,7 +334,7 @@
         mDisplayContent.mOpeningApps.add(win.mActivityRecord);
         try {
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
-                    new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
+                    new Point(50, 100), null, new Rect(50, 100, 150, 150), null).mAdapter;
             adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
                     mFinishedCallback);
             mController.goodToGo();
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 48a583c..53a3682 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -129,7 +129,7 @@
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
         final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
- 
+
         stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
         verify(organizer).taskAppeared(any());
         stack.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -345,7 +345,7 @@
             public void taskAppeared(RunningTaskInfo taskInfo) { }
 
             @Override
-            public void taskVanished(IWindowContainer container) { }
+            public void taskVanished(RunningTaskInfo container) { }
 
             @Override
             public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -399,7 +399,7 @@
             public void taskAppeared(RunningTaskInfo taskInfo) { }
 
             @Override
-            public void taskVanished(IWindowContainer container) { }
+            public void taskVanished(RunningTaskInfo container) { }
 
             @Override
             public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -539,7 +539,7 @@
             mInfo = info;
         }
         @Override
-        public void taskVanished(IWindowContainer wc) {
+        public void taskVanished(RunningTaskInfo info) {
         }
         @Override
         public void transactionReady(int id, SurfaceControl.Transaction t) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 52b465f..ea52d7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -36,7 +36,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.Display;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
@@ -71,18 +70,21 @@
     public void setUp() {
         TaskPositioner.setFactory(null);
 
-        final Display display = mDisplayContent.getDisplay();
-        final DisplayMetrics dm = new DisplayMetrics();
-        display.getMetrics(dm);
+        final DisplayMetrics dm = mDisplayContent.getDisplayMetrics();
 
         // This should be the same calculation as the TaskPositioner uses.
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
         removeGlobalMinSizeRestriction();
 
-        WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        mPositioner = new TaskPositioner(mWm, mWm.mAtmService);
-
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityRecord activity = new ActivityTestsBase.ActivityBuilder(stack.mAtmService)
+                .setStack(stack)
+                // In real case, there is no additional level for freeform mode.
+                .setCreateTask(false)
+                .build();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "window");
+        mPositioner = new TaskPositioner(mWm);
         mPositioner.register(mDisplayContent, win);
 
         win.getRootTask().setWindowingMode(WINDOWING_MODE_FREEFORM);
@@ -109,6 +111,28 @@
         assertTrue(created[0]);
     }
 
+    /** This tests that the window can move in all directions. */
+    @Test
+    public void testMoveWindow() {
+        final Rect displayBounds = mDisplayContent.getBounds();
+        final int windowSize = Math.min(displayBounds.width(), displayBounds.height()) / 2;
+        final int left = displayBounds.centerX() - windowSize / 2;
+        final int top = displayBounds.centerY() - windowSize / 2;
+        final Rect r = new Rect(left, top, left + windowSize, top + windowSize);
+        mPositioner.mTask.setBounds(r);
+        mPositioner.startDrag(false /* resizing */, false /* preserveOrientation */, left, top);
+
+        // Move upper left.
+        mPositioner.notifyMoveLocked(left - MOUSE_DELTA_X, top - MOUSE_DELTA_Y);
+        r.offset(-MOUSE_DELTA_X, -MOUSE_DELTA_Y);
+        assertBoundsEquals(r, mPositioner.getWindowDragBounds());
+
+        // Move bottom right.
+        mPositioner.notifyMoveLocked(left, top);
+        r.offset(MOUSE_DELTA_X, MOUSE_DELTA_Y);
+        assertBoundsEquals(r, mPositioner.getWindowDragBounds());
+    }
+
     /**
      * This tests that free resizing will allow to change the orientation as well
      * as does some basic tests (e.g. dragging in Y only will keep X stable).
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 35723ab..da4bde5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -16,9 +16,16 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
 import android.content.pm.PackageManager;
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -57,4 +64,25 @@
         return getInstrumentation().getTargetContext().getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_AUTOMOTIVE);
     }
+
+    @Test
+    public void testAddWindowToken() {
+        IBinder token = mock(IBinder.class);
+        mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId());
+
+        WindowToken windowToken = mWm.mRoot.getWindowToken(token);
+        assertFalse(windowToken.mRoundedCornerOverlay);
+        assertFalse(windowToken.mFromClientToken);
+    }
+
+    @Test
+    public void testAddWindowTokenWithOptions() {
+        IBinder token = mock(IBinder.class);
+        mWm.addWindowTokenWithOptions(token, TYPE_TOAST, mDisplayContent.getDisplayId(),
+                null /* options */, null /* options */);
+
+        WindowToken windowToken = mWm.mRoot.getWindowToken(token);
+        assertFalse(windowToken.mRoundedCornerOverlay);
+        assertTrue(windowToken.mFromClientToken);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index e6aed49..38f643d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -25,7 +25,9 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
+import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -129,4 +131,28 @@
         // Verify that the token windows are no longer attached to it.
         assertEquals(0, token.getWindowsCount());
     }
+
+    /**
+     * Test that {@link WindowToken} constructor parameters is set with expectation.
+     */
+    @Test
+    public void testWindowTokenConstructorSanity() {
+        WindowToken token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
+                TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent,
+                true /* ownerCanManageAppTokens */);
+        assertFalse(token.mRoundedCornerOverlay);
+        assertFalse(token.mFromClientToken);
+
+        token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST,
+                true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */,
+                true /* roundedCornerOverlay */);
+        assertTrue(token.mRoundedCornerOverlay);
+        assertFalse(token.mFromClientToken);
+
+        token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST,
+                true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */,
+                true /* roundedCornerOverlay */, true /* fromClientToken */);
+        assertTrue(token.mRoundedCornerOverlay);
+        assertTrue(token.mFromClientToken);
+    }
 }
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 9ae86c8..dcd4eb5 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -1,7 +1,6 @@
 package android.telephony;
 
 import android.annotation.IntDef;
-import android.provider.Telephony;
 import android.telecom.Connection;
 import android.telephony.data.ApnSetting;
 
@@ -653,15 +652,6 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface UiccAppType{}
 
-    /** @hide */
-    @IntDef({
-            Telephony.Carriers.SKIP_464XLAT_DEFAULT,
-            Telephony.Carriers.SKIP_464XLAT_DISABLE,
-            Telephony.Carriers.SKIP_464XLAT_ENABLE,
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Skip464XlatStatus {}
-
     /**
      * Override network type
      */
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c5c08c2..c20748b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1568,6 +1568,7 @@
     /**
      * The string is used to compare with operator name.
      * If it matches the pattern then show specific data icon.
+     * @hide
      */
     public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
             "show_carrier_data_icon_pattern_string";
@@ -2978,9 +2979,9 @@
      * UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not
      * define.
      * The configuration is: "connected_mmwave:5G_Plus,connected:5G"
+     * @hide
      */
-    public static final String KEY_5G_ICON_CONFIGURATION_STRING =
-            "5g_icon_configuration_string";
+    public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
 
     /**
      * Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is
@@ -2992,12 +2993,14 @@
      *
      * If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next
      * lost. Allows us to momentarily lose 5G without blinking the icon.
+     * @hide
      */
     public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT =
             "5g_icon_display_grace_period_sec_int";
 
     /**
      * Controls time in milliseconds until DcTracker reevaluates 5G connection state.
+     * @hide
      */
     public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
 
@@ -3527,6 +3530,15 @@
             "support_wps_over_ims_bool";
 
     /**
+     * The two digital number pattern of MMI code which is defined by carrier.
+     * If the dial number matches this pattern, it will be dialed out normally not USSD.
+     *
+     * @hide
+     */
+    public static final String KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY =
+            "mmi_two_digit_number_pattern_string_array";
+
+    /**
      * Holds the list of carrier certificate hashes.
      * Note that each carrier has its own certificates.
      */
@@ -4021,7 +4033,8 @@
         sDefaults.putBoolean(KEY_USE_CALLER_ID_USSD_BOOL, false);
         sDefaults.putInt(KEY_CALL_WAITING_SERVICE_CLASS_INT, 1 /* SERVICE_CLASS_VOICE */);
         sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
-                "connected_mmwave:5G,connected:5G");
+                "connected_mmwave:5G,connected:5G,not_restricted_rrc_idle:5G,"
+                        + "not_restricted_rrc_con:5G");
         sDefaults.putInt(KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT, 0);
         /* Default value is 1 hour. */
         sDefaults.putLong(KEY_5G_WATCHDOG_TIME_MS_LONG, 3600000);
@@ -4082,6 +4095,7 @@
                 new int[] {4 /* BUSY */});
         sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
         sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
+        sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
         sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
                 CellSignalStrengthLte.USE_RSRP);
         // Default wifi configurations.
diff --git a/telephony/java/android/telephony/CdmaEriInformation.java b/telephony/java/android/telephony/CdmaEriInformation.java
index 1cd9d30..fd0b905 100644
--- a/telephony/java/android/telephony/CdmaEriInformation.java
+++ b/telephony/java/android/telephony/CdmaEriInformation.java
@@ -40,7 +40,6 @@
  *
  * @hide
  */
-@SystemApi
 public final class CdmaEriInformation implements Parcelable {
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 270eafe..c667165 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -208,7 +208,6 @@
      * @return {@code true} if using carrier aggregation.
      * @hide
      */
-    @SystemApi
     public boolean isUsingCarrierAggregation() {
         return mIsUsingCarrierAggregation;
     }
diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java
index fe75266..34bac5d 100644
--- a/telephony/java/android/telephony/ImsManager.java
+++ b/telephony/java/android/telephony/ImsManager.java
@@ -34,8 +34,9 @@
     private Context mContext;
 
     /**
-     * <p>Broadcast Action: Indicates that an IMS operation was rejected by the network due to it
-     * not being authorized on the network.
+     * <p>Broadcast Action: Indicates that a previously allowed IMS operation was rejected by the
+     * network due to the network returning a "forbidden" response. This may be due to a
+     * provisioning change from the network.
      * May include the {@link SubscriptionManager#EXTRA_SUBSCRIPTION_INDEX} extra to also specify
      * which subscription the operation was rejected for.
      * <p class="note">
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c74e17f..1a79bf7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -367,6 +367,7 @@
      * Get the 5G NR connection state.
      *
      * @return the 5G NR connection state.
+     * @hide
      */
     public @NRState int getNrState() {
         return mNrState;
diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java
index c14bd91..98d6448 100644
--- a/telephony/java/android/telephony/PinResult.java
+++ b/telephony/java/android/telephony/PinResult.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -32,7 +31,6 @@
  *
  * @hide
  */
-@SystemApi
 public final class PinResult implements Parcelable {
     /** @hide */
     @IntDef({
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9b1baef..45cba51 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -689,8 +689,9 @@
      * @return true if registration indicates roaming, false otherwise
      * @hide
      */
-    @SystemApi
     public boolean getDataRoamingFromRegistration() {
+        // TODO: all callers should refactor to get roaming state directly from modem
+        // this should not be exposed as a public API
         return mIsDataRoamingFromRegistration;
     }
 
@@ -1422,7 +1423,6 @@
      * @return the frequency range of 5G NR.
      * @hide
      */
-    @SystemApi
     public @FrequencyRange int getNrFrequencyRange() {
         return mNrFrequencyRange;
     }
@@ -2026,6 +2026,7 @@
      * The long format can be up to 16 characters long.
      *
      * @return long raw name of operator, null if unregistered or unknown
+     * @hide
      */
     @Nullable
     public String getOperatorAlphaLongRaw() {
@@ -2045,6 +2046,7 @@
      * The short format can be up to 8 characters long.
      *
      * @return short raw name of operator, null if unregistered or unknown
+     * @hide
      */
     @Nullable
     public String getOperatorAlphaShortRaw() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 40def40..631eaac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -54,6 +54,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteException;
@@ -5605,7 +5606,6 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    @SystemApi
     @NonNull
     public CdmaEriInformation getCdmaEriInformation() {
         return new CdmaEriInformation(
@@ -8725,7 +8725,6 @@
      *
      * @hide
      */
-    @SystemApi
     @Nullable
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public PinResult supplyPinReportPinResult(@NonNull String pin) {
@@ -8750,7 +8749,6 @@
      *
      * @hide
      */
-    @SystemApi
     @Nullable
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public PinResult supplyPukReportPinResult(@NonNull String puk, @NonNull String pin) {
@@ -11648,11 +11646,9 @@
     }
 
     /**
-     * Override the file path for testing OTA emergency number database in a file partition.
+     * Override the file path for OTA emergency number database in a file partition.
      *
-     * @param otaFilePath The test OTA emergency number database file path;
-     *                    if "RESET", recover the original database file partition.
-     *                    Format: <root file folder>@<file path>
+     * @param otaParcelFileDescriptor parcelable file descriptor for OTA emergency number database.
      *
      * <p> Requires permission:
      * {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
@@ -11662,16 +11658,42 @@
     @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
     @SystemApi
     @TestApi
-    public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String otaFilePath) {
+    public void updateOtaEmergencyNumberDbFilePath(
+            @NonNull ParcelFileDescriptor otaParcelFileDescriptor) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null) {
-                telephony.updateTestOtaEmergencyNumberDbFilePath(otaFilePath);
+                telephony.updateOtaEmergencyNumberDbFilePath(otaParcelFileDescriptor);
             } else {
                 throw new IllegalStateException("telephony service is null.");
             }
         } catch (RemoteException ex) {
-            Log.e(TAG, "notifyOtaEmergencyNumberDatabaseInstalled RemoteException", ex);
+            Log.e(TAG, "updateOtaEmergencyNumberDbFilePath RemoteException", ex);
+            ex.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Reset the file path to default for OTA emergency number database in a file partition.
+     *
+     * <p> Requires permission:
+     * {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION}
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION)
+    @SystemApi
+    @TestApi
+    public void resetOtaEmergencyNumberDbFilePath() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.resetOtaEmergencyNumberDbFilePath();
+            } else {
+                throw new IllegalStateException("telephony service is null.");
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "resetOtaEmergencyNumberDbFilePath RemoteException", ex);
             ex.rethrowAsRuntimeException();
         }
     }
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index f5dfacc6..bfb54b0 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -18,7 +18,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.SystemApi;
 import android.content.ContentValues;
 import android.database.Cursor;
 import android.hardware.radio.V1_5.ApnTypes;
@@ -27,7 +26,6 @@
 import android.os.Parcelable;
 import android.provider.Telephony;
 import android.provider.Telephony.Carriers;
-import android.telephony.Annotation;
 import android.telephony.Annotation.ApnType;
 import android.telephony.Annotation.NetworkType;
 import android.telephony.ServiceState;
@@ -126,6 +124,15 @@
     /** Authentication type for PAP or CHAP. */
     public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
 
+    /** @hide */
+    @IntDef({
+            Telephony.Carriers.SKIP_464XLAT_DEFAULT,
+            Telephony.Carriers.SKIP_464XLAT_DISABLE,
+            Telephony.Carriers.SKIP_464XLAT_ENABLE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Skip464XlatStatus {}
+
     /**
      * APN types for data connections.  These are usage categories for an APN
      * entry.  One APN entry may support multiple APN types, eg, a single APN
@@ -139,7 +146,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_ALL_STRING = "*";
 
     /**
@@ -147,7 +153,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_DEFAULT_STRING = "default";
 
 
@@ -156,7 +161,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_MMS_STRING = "mms";
 
 
@@ -165,7 +169,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_SUPL_STRING = "supl";
 
     /**
@@ -173,7 +176,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_DUN_STRING = "dun";
 
     /**
@@ -181,7 +183,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_HIPRI_STRING = "hipri";
 
     /**
@@ -189,7 +190,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_FOTA_STRING = "fota";
 
     /**
@@ -197,7 +197,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_IMS_STRING = "ims";
 
     /**
@@ -205,7 +204,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_CBS_STRING = "cbs";
 
     /**
@@ -213,7 +211,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_IA_STRING = "ia";
 
     /**
@@ -222,7 +219,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_EMERGENCY_STRING = "emergency";
 
     /**
@@ -230,7 +226,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_MCX_STRING = "mcx";
 
     /**
@@ -238,7 +233,6 @@
      *
      * @hide
      */
-    @SystemApi
     public static final String TYPE_XCAP_STRING = "xcap";
 
 
@@ -745,7 +739,7 @@
      * @return SKIP_464XLAT_DEFAULT, SKIP_464XLAT_DISABLE or SKIP_464XLAT_ENABLE
      * @hide
      */
-    @Annotation.Skip464XlatStatus
+    @Skip464XlatStatus
     public int getSkip464Xlat() {
         return mSkip464Xlat;
     }
@@ -1416,7 +1410,6 @@
      * @return comma delimited list of APN types.
      * @hide
      */
-    @SystemApi
     @NonNull
     public static String getApnTypesStringFromBitmask(int apnTypeBitmask) {
         List<String> types = new ArrayList<>();
@@ -2065,7 +2058,7 @@
          * @param skip464xlat skip464xlat for this APN.
          * @hide
          */
-        public Builder setSkip464Xlat(@Annotation.Skip464XlatStatus int skip464xlat) {
+        public Builder setSkip464Xlat(@Skip464XlatStatus int skip464xlat) {
             this.mSkip464Xlat = skip464xlat;
             return this;
         }
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 9c1be48..1597cd5 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -18,7 +18,6 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -718,11 +717,16 @@
      * @return A {@link Bundle} containing proprietary call extras that were not set by the
      * platform.
      */
-    public @Nullable Bundle getProprietaryCallExtras() {
+    public @NonNull Bundle getProprietaryCallExtras() {
         if (mCallExtras == null) {
-            return null;
+            return new Bundle();
         }
-        return mCallExtras.getBundle(EXTRA_OEM_EXTRAS);
+        Bundle proprietaryExtras = mCallExtras.getBundle(EXTRA_OEM_EXTRAS);
+        if (proprietaryExtras == null) {
+            return new Bundle();
+        }
+        // Make a copy so users do not accidentally change this copy of the extras.
+        return new Bundle(proprietaryExtras);
     }
 
     public ImsStreamMediaProfile getMediaProfile() {
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 025721c..81af99f 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -58,7 +58,7 @@
         try {
             mListener.callSessionProgressing(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -71,7 +71,7 @@
         try {
             mListener.callSessionInitiated(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -85,7 +85,7 @@
         try {
             mListener.callSessionInitiatedFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -98,7 +98,7 @@
         try {
             mListener.callSessionTerminated(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -115,7 +115,7 @@
         try {
             mListener.callSessionHeld(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -128,7 +128,7 @@
         try {
             mListener.callSessionHoldFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -141,7 +141,7 @@
         try {
             mListener.callSessionHoldReceived(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -155,7 +155,7 @@
         try {
             mListener.callSessionResumed(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -169,7 +169,7 @@
         try {
             mListener.callSessionResumeFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -182,7 +182,7 @@
         try {
             mListener.callSessionResumeReceived(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -201,7 +201,7 @@
             mListener.callSessionMergeStarted(newSession != null ?
                             newSession.getServiceImpl() : null, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -216,7 +216,7 @@
         try {
             mListener.callSessionMergeStarted(newSession, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -232,7 +232,7 @@
             mListener.callSessionMergeComplete(newSession != null ?
                     newSession.getServiceImpl() : null);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -247,7 +247,7 @@
         try {
             mListener.callSessionMergeComplete(newSession);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -260,7 +260,7 @@
         try {
             mListener.callSessionMergeFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -273,7 +273,7 @@
         try {
             mListener.callSessionUpdated(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -286,7 +286,7 @@
         try {
             mListener.callSessionUpdateFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -299,7 +299,7 @@
         try {
             mListener.callSessionUpdateReceived(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -319,7 +319,7 @@
             mListener.callSessionConferenceExtended(
                     newSession != null ? newSession.getServiceImpl() : null, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -333,7 +333,7 @@
         try {
             mListener.callSessionConferenceExtended(newSession, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -347,7 +347,7 @@
         try {
             mListener.callSessionConferenceExtendFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -364,7 +364,7 @@
             mListener.callSessionConferenceExtendReceived(newSession != null
                     ? newSession.getServiceImpl() : null, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -379,7 +379,7 @@
         try {
             mListener.callSessionConferenceExtendReceived(newSession, profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -391,7 +391,7 @@
         try {
             mListener.callSessionInviteParticipantsRequestDelivered();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -407,7 +407,7 @@
         try {
             mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -419,7 +419,7 @@
         try {
             mListener.callSessionRemoveParticipantsRequestDelivered();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -435,7 +435,7 @@
         try {
             mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -448,7 +448,7 @@
         try {
             mListener.callSessionConferenceStateUpdated(state);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -465,7 +465,7 @@
         try {
             mListener.callSessionUssdMessageReceived(mode, ussdMessage);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -501,7 +501,7 @@
         try {
             mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -537,7 +537,7 @@
         try {
             mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -570,7 +570,7 @@
         try {
             mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -587,7 +587,7 @@
         try {
             mListener.callSessionTtyModeReceived(mode);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -600,7 +600,7 @@
         try {
             mListener.callSessionMultipartyStateChanged(isMultiParty);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -614,7 +614,7 @@
         try {
             mListener.callSessionSuppServiceReceived(suppSrvNotification);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -628,7 +628,7 @@
         try {
             mListener.callSessionRttModifyRequestReceived(callProfile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -641,7 +641,7 @@
         try {
             mListener.callSessionRttModifyResponseReceived(status);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -654,7 +654,7 @@
         try {
             mListener.callSessionRttMessageReceived(rttMessage);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -667,7 +667,7 @@
         try {
             mListener.callSessionRttAudioIndicatorChanged(profile);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 
@@ -680,7 +680,7 @@
         try {
             mListener.callQualityChanged(callQuality);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            e.rethrowFromSystemServer();
         }
     }
 }
diff --git a/telephony/java/android/telephony/ims/ImsUtListener.java b/telephony/java/android/telephony/ims/ImsUtListener.java
index bc124044..460a032 100644
--- a/telephony/java/android/telephony/ims/ImsUtListener.java
+++ b/telephony/java/android/telephony/ims/ImsUtListener.java
@@ -49,7 +49,8 @@
      * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_RESTRICTED}, and
      * {@link ImsSsInfo#CLIR_STATUS_TEMPORARILY_ALLOWED}.
      * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
-     * instead.
+     * instead, this key has been added for backwards compatibility with older proprietary
+     * implementations only and is being phased out.
      */
     @Deprecated
     public static final String BUNDLE_KEY_CLIR = "queryClir";
@@ -60,7 +61,8 @@
      * response. The value will be an instance of {@link ImsSsInfo}, which contains the response to
      * the query.
      * @deprecated Use {@link #onLineIdentificationSupplementaryServiceResponse(int, ImsSsInfo)}
-     * instead.
+     * instead, this key has been added for backwards compatibility with older proprietary
+     * implementations only and is being phased out.
      */
     @Deprecated
     public static final String BUNDLE_KEY_SSINFO = "imsSsInfo";
@@ -123,7 +125,7 @@
         try {
             mServiceInterface.lineIdentificationSupplementaryServiceResponse(id, configuration);
         } catch (RemoteException e) {
-            Log.w(LOG_TAG, "onLineIdentificationSupplementaryServicesResponse: remote exception");
+            e.rethrowFromSystemServer();
         }
     }
 
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 0370846..00fa942 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -305,13 +305,13 @@
 
     /**
      * An integer key associated with the carrier configured expiration time in seconds for
-     * RCS presence published offline availability in RCS presence.
+     * published offline availability in RCS presence provided, which is provided to the network.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
      */
-    public static final int KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC = 16;
+    public static final int KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC = 16;
 
     /**
      * An integer key associated with whether or not capability discovery is provisioned for this
@@ -326,8 +326,10 @@
     public static final int KEY_RCS_CAPABILITY_DISCOVERY_ENABLED = 17;
 
     /**
-     * An integer key associated with the period of time the capability information of each contact
-     * is cached on the device.
+     * An integer key associated with the period of time in seconds the capability information of
+     * each contact is cached on the device.
+     * <p>
+     * Seconds are used because this is usually measured in the span of days.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
@@ -337,7 +339,8 @@
 
     /**
      * An integer key associated with the period of time in seconds that the availability
-     * information of a contact is cached on the device.
+     * information of a contact is cached on the device, which is based on the carrier provisioning
+     * configuration from the network.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
@@ -347,7 +350,8 @@
 
     /**
      * An integer key associated with the carrier configured interval in seconds expected between
-     * successive capability polling attempts.
+     * successive capability polling attempts, which is based on the carrier provisioning
+     * configuration from the network.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
@@ -357,7 +361,7 @@
 
     /**
      * An integer key representing the minimum time allowed between two consecutive presence publish
-     * messages from the device.
+     * messages from the device in milliseconds.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
@@ -378,7 +382,7 @@
     /**
      * An integer associated with the expiration timer used during the SIP subscription of a
      * Request Contained List (RCL), which is used to retrieve the RCS capabilities of the contact
-     * book.
+     * book. This timer value is sent in seconds to the network.
      * <p>
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
@@ -470,7 +474,8 @@
     public static final int KEY_SIP_KEEP_ALIVE_ENABLED = 32;
 
     /**
-     * Registration retry Base Time value in seconds.
+     * Registration retry Base Time value in seconds, which is based off of the carrier
+     * configuration.
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
@@ -478,7 +483,8 @@
     public static final int KEY_REGISTRATION_RETRY_BASE_TIME_SEC = 33;
 
     /**
-     * Registration retry Max Time value in seconds.
+     * Registration retry Max Time value in seconds, which is based off of the carrier
+     * configuration.
      * Value is in Integer format.
      * @see #setProvisioningIntValue(int, int)
      * @see #getProvisioningIntValue(int)
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 58e9b70..30306c7 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -24,12 +24,10 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.content.Context;
-import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.provider.Telephony;
 import android.telephony.TelephonyFrameworkInitializer;
 import android.telephony.ims.aidl.IImsRcsController;
 import android.telephony.ims.aidl.IRcsUceControllerCallback;
@@ -138,7 +136,7 @@
      * UCE.
      * @hide
      */
-    public static final int PUBLISH_STATE_200_OK = 1;
+    public static final int PUBLISH_STATE_OK = 1;
 
     /**
      * The hasn't published its capabilities since boot or hasn't gotten any publish response yet.
@@ -178,7 +176,7 @@
     /**@hide*/
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "PUBLISH_STATE_", value = {
-            PUBLISH_STATE_200_OK,
+            PUBLISH_STATE_OK,
             PUBLISH_STATE_NOT_PUBLISHED,
             PUBLISH_STATE_VOLTE_PROVISION_ERROR,
             PUBLISH_STATE_RCS_PROVISION_ERROR,
@@ -305,7 +303,7 @@
      * Gets the last publish result from the UCE service if the device is using an RCS presence
      * server.
      * @return The last publish result from the UCE service. If the device is using SIP OPTIONS,
-     * this method will return {@link #PUBLISH_STATE_200_OK} as well.
+     * this method will return {@link #PUBLISH_STATE_OK} as well.
      * @throws ImsException if the subscription associated with this instance of
      * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not
      * available. This can happen if the ImsService has crashed, for example, or if the subscription
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 96f77d8..d0cec52d 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -270,11 +270,12 @@
         /**
          * Requested expiration for Published Offline availability.
          * Value is in Integer format.
-         * @deprecated use {@link ProvisioningManager#KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC}.
+         * @deprecated use
+         *     {@link ProvisioningManager#KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC}.
          */
         @Deprecated
         public static final int PUBLISH_TIMER_EXTENDED =
-                ProvisioningManager.KEY_RCS_PUBLISH_TIMER_EXTENDED_SEC;
+                ProvisioningManager.KEY_RCS_PUBLISH_OFFLINE_AVAILABILITY_TIMER_SEC;
 
         /**
          *
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index af5089f..dcf339c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Messenger;
+import android.os.ParcelFileDescriptor;
 import android.os.ResultReceiver;
 import android.os.WorkSource;
 import android.net.NetworkStats;
@@ -2121,9 +2122,14 @@
     void notifyOtaEmergencyNumberDbInstalled();
 
     /**
-     * Override the file partition name for testing OTA emergency number database.
+     * Override a customized file partition name for OTA emergency number database.
      */
-    void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath);
+    void updateOtaEmergencyNumberDbFilePath(in ParcelFileDescriptor otaParcelFileDescriptor);
+
+    /**
+     * Reset file partition to default for OTA emergency number database.
+     */
+    void resetOtaEmergencyNumberDbFilePath();
 
     /**
      * Enable or disable a logical modem stack associated with the slotIndex.
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index 8283019..8f4bccc 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -25,6 +25,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -172,7 +173,7 @@
      * from observers elsewhere in the system.
      */
     @Override
-    public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+    public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
             @NotifyFlags int flags) {
     }
 }
diff --git a/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
new file mode 100644
index 0000000..2fbfeba
--- /dev/null
+++ b/tests/PackageWatchdog/src/com/android/server/ExplicitHealthCheckServiceTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.IExplicitHealthCheckService;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+
+public class ExplicitHealthCheckServiceTest {
+
+    private ExplicitHealthCheckService mExplicitHealthCheckService;
+    private static final String PACKAGE_NAME = "com.test.package";
+
+    @Before
+    public void setup() throws Exception {
+        mExplicitHealthCheckService = spy(ExplicitHealthCheckService.class);
+    }
+
+    /**
+     * Test to verify that the correct information is sent in the callback when a package has
+     * passed an explicit health check.
+     */
+    @Test
+    public void testNotifyHealthCheckPassed() throws Exception {
+        IBinder binder = mExplicitHealthCheckService.onBind(new Intent());
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        RemoteCallback callback = new RemoteCallback(result -> {
+            assertThat(result.get(ExplicitHealthCheckService.EXTRA_HEALTH_CHECK_PASSED_PACKAGE))
+                    .isEqualTo(PACKAGE_NAME);
+            countDownLatch.countDown();
+        });
+        IExplicitHealthCheckService.Stub.asInterface(binder).setCallback(callback);
+        mExplicitHealthCheckService.notifyHealthCheckPassed(PACKAGE_NAME);
+        countDownLatch.await();
+    }
+}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 8cc8cf4..819fc02 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1063,6 +1063,52 @@
         assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
     }
 
+    /**
+     * Test to verify that Package Watchdog syncs health check requests with the controller
+     * correctly, and that the requests are only synced when the set of observed packages
+     * changes.
+     */
+    @Test
+    public void testSyncHealthCheckRequests() {
+        TestController testController = spy(TestController.class);
+        testController.setSupportedPackages(List.of(APP_A, APP_B, APP_C));
+        PackageWatchdog watchdog = createWatchdog(testController, true);
+
+        TestObserver testObserver1 = new TestObserver(OBSERVER_NAME_1);
+        watchdog.registerHealthObserver(testObserver1);
+        watchdog.startObservingHealth(testObserver1, List.of(APP_A), LONG_DURATION);
+        mTestLooper.dispatchAll();
+
+        TestObserver testObserver2 = new TestObserver(OBSERVER_NAME_2);
+        watchdog.registerHealthObserver(testObserver2);
+        watchdog.startObservingHealth(testObserver2, List.of(APP_B), LONG_DURATION);
+        mTestLooper.dispatchAll();
+
+        TestObserver testObserver3 = new TestObserver(OBSERVER_NAME_3);
+        watchdog.registerHealthObserver(testObserver3);
+        watchdog.startObservingHealth(testObserver3, List.of(APP_C), LONG_DURATION);
+        mTestLooper.dispatchAll();
+
+        watchdog.unregisterHealthObserver(testObserver1);
+        mTestLooper.dispatchAll();
+
+        watchdog.unregisterHealthObserver(testObserver2);
+        mTestLooper.dispatchAll();
+
+        watchdog.unregisterHealthObserver(testObserver3);
+        mTestLooper.dispatchAll();
+
+        List<Set> expectedSyncRequests = List.of(
+                Set.of(APP_A),
+                Set.of(APP_A, APP_B),
+                Set.of(APP_A, APP_B, APP_C),
+                Set.of(APP_B, APP_C),
+                Set.of(APP_C),
+                Set.of()
+        );
+        assertThat(testController.getSyncRequests()).isEqualTo(expectedSyncRequests);
+    }
+
     private void adoptShellPermissions(String... permissions) {
         InstrumentationRegistry
                 .getInstrumentation()
@@ -1219,6 +1265,7 @@
         private Consumer<String> mPassedConsumer;
         private Consumer<List<PackageConfig>> mSupportedConsumer;
         private Runnable mNotifySyncRunnable;
+        private List<Set> mSyncRequests = new ArrayList<>();
 
         @Override
         public void setEnabled(boolean enabled) {
@@ -1238,6 +1285,7 @@
 
         @Override
         public void syncRequests(Set<String> packages) {
+            mSyncRequests.add(packages);
             mRequestedPackages.clear();
             if (mIsEnabled) {
                 packages.retainAll(mSupportedPackages);
@@ -1268,6 +1316,10 @@
                 return Collections.emptyList();
             }
         }
+
+        public List<Set> getSyncRequests() {
+            return mSyncRequests;
+        }
     }
 
     private static class TestClock implements PackageWatchdog.SystemClock {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 70be83f..a616c61 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -127,18 +127,12 @@
 
     /**
      * Test rollbacks of staged installs involving only apks with bad update.
-     * Trigger rollback phase. This is expected to fail due to watchdog
-     * rebooting the test out from under it.
+     * Trigger rollback phase.
      */
     @Test
     public void testBadApkOnly_Phase3() throws Exception {
         // One more crash to trigger rollback
         RollbackUtils.sendCrashBroadcast(TestApp.A, 1);
-
-        // We expect the device to be rebooted automatically. Wait for that to happen.
-        // This device method will fail and the host will catch the assertion.
-        // If reboot doesn't happen, the host will fail the assertion.
-        Thread.sleep(TimeUnit.SECONDS.toMillis(120));
     }
 
     /**
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 4afebb5..282f012 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -22,7 +22,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
-import static org.testng.Assert.assertThrows;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -136,7 +135,10 @@
         getDevice().reboot();
         runPhase("testBadApkOnly_Phase2");
 
-        assertThrows(AssertionError.class, () -> runPhase("testBadApkOnly_Phase3"));
+        // Trigger rollback and wait for reboot to happen
+        runPhase("testBadApkOnly_Phase3");
+        assertTrue(getDevice().waitForDeviceNotAvailable(TimeUnit.MINUTES.toMillis(2)));
+
         getDevice().waitForDeviceAvailable();
 
         runPhase("testBadApkOnly_Phase4");
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 8f7bebb..6eb4587 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -139,7 +139,7 @@
                 mTaskView2.reparentTask(ti.token);
             }
         }
-        public void taskVanished(IWindowContainer wc) {
+        public void taskVanished(ActivityManager.RunningTaskInfo ti) {
         }
         public void transactionReady(int id, SurfaceControl.Transaction t) {
             mergedTransaction.merge(t);
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index bd17751..ade5c2e 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -49,7 +49,7 @@
             } catch (Exception e) {
             }
         }
-        public void taskVanished(IWindowContainer wc) {
+        public void taskVanished(ActivityManager.RunningTaskInfo ti) {
         }
         public void transactionReady(int id, SurfaceControl.Transaction t) {
         }
diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java
index ca4ba63..7a60cc1 100644
--- a/tests/net/common/java/android/net/CaptivePortalTest.java
+++ b/tests/net/common/java/android/net/CaptivePortalTest.java
@@ -18,19 +18,26 @@
 
 import static org.junit.Assert.assertEquals;
 
+import android.os.Build;
 import android.os.RemoteException;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
 
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class CaptivePortalTest {
+    @Rule
+    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
     private static final int DEFAULT_TIMEOUT_MS = 5000;
     private static final String TEST_PACKAGE_NAME = "com.google.android.test";
 
@@ -84,6 +91,7 @@
         assertEquals(result.mCode, CaptivePortal.APP_RETURN_WANTED_AS_IS);
     }
 
+    @IgnoreUpTo(Build.VERSION_CODES.Q)
     @Test
     public void testReevaluateNetwork() {
         final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.reevaluateNetwork());
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 06c6301..99dac14 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -28,8 +28,8 @@
 import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
 
 import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
 import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
 import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
 
 import static org.junit.Assert.assertEquals;
@@ -38,11 +38,17 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.os.Build;
 import android.os.SystemClock;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -57,6 +63,8 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class LinkAddressTest {
+    @Rule
+    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
@@ -318,15 +326,29 @@
 
         l = new LinkAddress(V6_ADDRESS, 64, 123, 456);
         assertParcelingIsLossless(l);
-        l = new LinkAddress(V6_ADDRESS, 64, 123, 456,
-                1L, 3600000L);
-        assertParcelingIsLossless(l);
 
         l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK);
-        assertParcelSane(l, 6);
+        assertParcelingIsLossless(l);
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testLifetimeParceling() {
+        final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, 456, 1L, 3600000L);
+        assertParcelingIsLossless(l);
+    }
+
+    @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+    public void testFieldCount_Q() {
+        assertFieldCountEquals(4, LinkAddress.class);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testFieldCount() {
+        // Make sure any new field is covered by the above parceling tests when changing this number
+        assertFieldCountEquals(6, LinkAddress.class);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testDeprecationTime() {
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
@@ -347,7 +369,7 @@
         } catch (IllegalArgumentException expected) { }
     }
 
-    @Test
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testExpirationTime() {
         try {
             new LinkAddress(V6_ADDRESS, 64, 0, 456,
@@ -366,10 +388,13 @@
     public void testGetFlags() {
         LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 123, RT_SCOPE_HOST);
         assertEquals(123, l.getFlags());
+    }
 
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testGetFlags_Deprecation() {
         // Test if deprecated bit was added/remove automatically based on the provided deprecation
         // time
-        l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
+        LinkAddress l = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_HOST,
                 1L, LinkAddress.LIFETIME_PERMANENT);
         // Check if the flag is added automatically.
         assertTrue((l.getFlags() & IFA_F_DEPRECATED) != 0);
@@ -458,8 +483,11 @@
                             (IFA_F_TEMPORARY|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC),
                             RT_SCOPE_UNIVERSE);
         assertGlobalPreferred(l, "v6,global,tempaddr+optimistic");
+    }
 
-        l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testIsGlobalPreferred_DeprecatedInFuture() {
+        final LinkAddress l = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED,
                 RT_SCOPE_UNIVERSE, SystemClock.elapsedRealtime() + 100000,
                 SystemClock.elapsedRealtime() + 200000);
         // Although the deprecated bit is set, but the deprecation time is in the future, test
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index f25fd4d..48b65e5 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -315,7 +315,7 @@
         source.addDnsServer(DNS1);
         source.addDnsServer(DNS2);
         // set 2 gateways
-        source.addRoute(new RouteInfo(GATEWAY1));
+        source.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
         source.addRoute(new RouteInfo(GATEWAY2));
         source.setMtu(MTU);
 
@@ -327,7 +327,7 @@
         target.addDnsServer(DNS2);
         target.addDnsServer(DNS1);
         target.addRoute(new RouteInfo(GATEWAY2));
-        target.addRoute(new RouteInfo(GATEWAY1));
+        target.addRoute(new RouteInfo(LINKADDRV4, GATEWAY1));
         target.setMtu(MTU);
 
         assertLinkPropertiesEqual(source, target);
@@ -364,12 +364,13 @@
 
     @Test
     public void testRouteInterfaces() {
-        LinkAddress prefix = new LinkAddress(address("2001:db8::"), 32);
+        LinkAddress prefix1 = new LinkAddress(address("2001:db8:1::"), 48);
+        LinkAddress prefix2 = new LinkAddress(address("2001:db8:2::"), 48);
         InetAddress address = ADDRV6;
 
         // Add a route with no interface to a LinkProperties with no interface. No errors.
         LinkProperties lp = new LinkProperties();
-        RouteInfo r = new RouteInfo(prefix, address, null);
+        RouteInfo r = new RouteInfo(prefix1, address, null);
         assertTrue(lp.addRoute(r));
         assertEquals(1, lp.getRoutes().size());
         assertAllRoutesHaveInterface(null, lp);
@@ -379,7 +380,7 @@
         assertEquals(1, lp.getRoutes().size());
 
         // Add a route with an interface. Expect an exception.
-        r = new RouteInfo(prefix, address, "wlan0");
+        r = new RouteInfo(prefix2, address, "wlan0");
         try {
           lp.addRoute(r);
           fail("Adding wlan0 route to LP with no interface, expect exception");
@@ -398,7 +399,7 @@
         } catch (IllegalArgumentException expected) {}
 
         // If the interface name matches, the route is added.
-        r = new RouteInfo(prefix, null, "wlan0");
+        r = new RouteInfo(prefix2, null, "wlan0");
         lp.setInterfaceName("wlan0");
         lp.addRoute(r);
         assertEquals(2, lp.getRoutes().size());
@@ -423,10 +424,12 @@
         assertEquals(3, lp.compareAllRoutes(lp2).added.size());
         assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
 
-        // Check remove works
-        lp.removeRoute(new RouteInfo(prefix, address, null));
+        // Remove route with incorrect interface, no route removed.
+        lp.removeRoute(new RouteInfo(prefix2, null, null));
         assertEquals(3, lp.getRoutes().size());
-        lp.removeRoute(new RouteInfo(prefix, address, "wlan0"));
+
+        // Check remove works when interface is correct.
+        lp.removeRoute(new RouteInfo(prefix2, null, "wlan0"));
         assertEquals(2, lp.getRoutes().size());
         assertAllRoutesHaveInterface("wlan0", lp);
         assertAllRoutesNotHaveInterface("p2p0", lp);
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index d250ad3..173dbd1 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -16,16 +16,23 @@
 
 package android.net
 
+import android.os.Build
 import androidx.test.filters.SmallTest
 import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
 import com.android.testutils.assertParcelSane
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class NetworkAgentConfigTest {
-    @Test
+    @Rule @JvmField
+    val ignoreRule = DevSdkIgnoreRule()
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     fun testParcelNetworkAgentConfig() {
         val config = NetworkAgentConfig.Builder().apply {
             setExplicitlySelected(true)
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
deleted file mode 100644
index 30836b7..0000000
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net
-
-import android.os.Parcelable
-import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
-import com.android.testutils.assertParcelSane
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
-import org.junit.Assert.assertNotEquals
-import org.junit.Assert.assertTrue
-import org.junit.Test
-import org.junit.runner.RunWith
-
-private const val TEST_SCORE = 80
-private const val KEY_DEFAULT_CAPABILITIES = "DEFAULT_CAPABILITIES"
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-class NetworkScoreTest {
-    @Test
-    fun testParcelNetworkScore() {
-        val networkScore = NetworkScore()
-        val defaultCap = NetworkCapabilities()
-        networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
-        assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
-        networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
-        assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
-        assertParcelSane(networkScore, 1)
-    }
-
-    @Test
-    fun testNullKeyAndValue() {
-        val networkScore = NetworkScore()
-        val defaultCap = NetworkCapabilities()
-        networkScore.putIntExtension(null, TEST_SCORE)
-        assertEquals(TEST_SCORE, networkScore.getIntExtension(null))
-        networkScore.putExtension(null, defaultCap)
-        assertEquals(defaultCap, networkScore.getExtension(null))
-        networkScore.putExtension(null, null)
-        val result: Parcelable? = networkScore.getExtension(null)
-        assertEquals(null, result)
-    }
-
-    @Test
-    fun testRemoveExtension() {
-        val networkScore = NetworkScore()
-        val defaultCap = NetworkCapabilities()
-        networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
-        networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
-        assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
-        assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
-        networkScore.removeExtension(KEY_DEFAULT_CAPABILITIES)
-        networkScore.removeExtension(NetworkScore.LEGACY_SCORE)
-        val result: Parcelable? = networkScore.getExtension(KEY_DEFAULT_CAPABILITIES)
-        assertEquals(null, result)
-        assertEquals(0, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
-    }
-
-    @Test
-    fun testEqualsNetworkScore() {
-        val ns1 = NetworkScore()
-        val ns2 = NetworkScore()
-        assertTrue(ns1.equals(ns2))
-        assertEquals(ns1.hashCode(), ns2.hashCode())
-
-        ns1.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
-        assertFalse(ns1.equals(ns2))
-        assertNotEquals(ns1.hashCode(), ns2.hashCode())
-        ns2.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
-        assertTrue(ns1.equals(ns2))
-        assertEquals(ns1.hashCode(), ns2.hashCode())
-
-        val defaultCap = NetworkCapabilities()
-        ns1.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
-        assertFalse(ns1.equals(ns2))
-        assertNotEquals(ns1.hashCode(), ns2.hashCode())
-        ns2.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
-        assertTrue(ns1.equals(ns2))
-        assertEquals(ns1.hashCode(), ns2.hashCode())
-
-        ns1.putIntExtension(null, 10)
-        assertFalse(ns1.equals(ns2))
-        assertNotEquals(ns1.hashCode(), ns2.hashCode())
-        ns2.putIntExtension(null, 10)
-        assertTrue(ns1.equals(ns2))
-        assertEquals(ns1.hashCode(), ns2.hashCode())
-    }
-}
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index fe51b3a..1658262 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -19,19 +19,40 @@
 import static android.net.RouteInfo.RTN_UNREACHABLE;
 
 import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
 import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
 import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
 
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import junit.framework.TestCase;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 
-public class RouteInfoTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteInfoTest {
+    @Rule
+    public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
+    private static final int INVALID_ROUTE_TYPE = -1;
 
     private InetAddress Address(String addr) {
         return InetAddress.parseNumericAddress(addr);
@@ -41,15 +62,32 @@
         return new IpPrefix(prefix);
     }
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         RouteInfo r;
-
         // Invalid input.
         try {
             r = new RouteInfo((IpPrefix) null, null, "rmnet0");
             fail("Expected RuntimeException:  destination and gateway null");
-        } catch(RuntimeException e) {}
+        } catch (RuntimeException e) { }
+
+        try {
+            r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
+                    INVALID_ROUTE_TYPE);
+            fail("Invalid route type should cause exception");
+        } catch (IllegalArgumentException e) { }
+
+        try {
+            r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
+                    RTN_UNREACHABLE);
+            fail("Address family mismatch should cause exception");
+        } catch (IllegalArgumentException e) { }
+
+        try {
+            r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
+                    RTN_UNREACHABLE);
+            fail("Address family mismatch should cause exception");
+        } catch (IllegalArgumentException e) { }
 
         // Null destination is default route.
         r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
@@ -74,6 +112,7 @@
         assertNull(r.getInterface());
     }
 
+    @Test
     public void testMatches() {
         class PatchedRouteInfo {
             private final RouteInfo mRouteInfo;
@@ -113,6 +152,7 @@
         assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
     }
 
+    @Test
     public void testEquals() {
         // IPv4
         RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
@@ -146,6 +186,7 @@
         assertNotEqualEitherWay(r1, r3);
     }
 
+    @Test
     public void testHostAndDefaultRoutes() {
         RouteInfo r;
 
@@ -228,6 +269,7 @@
         assertFalse(r.isIPv6Default());
     }
 
+    @Test
     public void testTruncation() {
       LinkAddress l;
       RouteInfo r;
@@ -244,6 +286,7 @@
     // Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
     // there's nothing we can do with them, we don't want to crash if, e.g., someone calls
     // requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
+    @Test
     public void testMulticastRoute() {
       RouteInfo r;
       r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
@@ -251,16 +294,36 @@
       // No exceptions? Good.
     }
 
+    @Test
     public void testParceling() {
         RouteInfo r;
-
-        r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
+        r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
         assertParcelingIsLossless(r);
-
         r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
-        assertParcelSane(r, 7);
+        assertParcelingIsLossless(r);
+        r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
+        assertParcelingIsLossless(r);
     }
 
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testMtuParceling() {
+        final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
+                RTN_UNREACHABLE, 1450 /* mtu */);
+        assertParcelingIsLossless(r);
+    }
+
+    @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+    public void testFieldCount_Q() {
+        assertFieldCountEquals(6, RouteInfo.class);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+    public void testFieldCount() {
+        // Make sure any new field is covered by the above parceling tests when changing this number
+        assertFieldCountEquals(7, RouteInfo.class);
+    }
+
+    @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
     public void testMtu() {
         RouteInfo r;
         r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4e75f2a2..8c0c36b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -2751,9 +2751,6 @@
 
         // Expect NET_CAPABILITY_VALIDATED onAvailable callback.
         validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
-        // Expect no notification to be shown when captive portal disappears by itself
-        verify(mNotificationManager, never()).notifyAsUser(
-                anyString(), eq(NotificationType.LOGGED_IN.eventId), any(), any());
 
         // Break network connectivity.
         // Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -2815,8 +2812,6 @@
         mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
         validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
         captivePortalCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
-        verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
-                eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
 
         mCm.unregisterNetworkCallback(validatedCallback);
         mCm.unregisterNetworkCallback(captivePortalCallback);
@@ -5927,6 +5922,12 @@
         final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
         final String kNat64PrefixString = "2001:db8:64:64:64:64::";
         final IpPrefix kNat64Prefix = new IpPrefix(InetAddress.getByName(kNat64PrefixString), 96);
+        final RouteInfo defaultRoute = new RouteInfo((IpPrefix) null, myIpv6.getAddress(),
+                                                     MOBILE_IFNAME);
+        final RouteInfo ipv6Subnet = new RouteInfo(myIpv6, null, MOBILE_IFNAME);
+        final RouteInfo ipv4Subnet = new RouteInfo(myIpv4, null, MOBILE_IFNAME);
+        final RouteInfo stackedDefault = new RouteInfo((IpPrefix) null, myIpv4.getAddress(),
+                                                       CLAT_PREFIX + MOBILE_IFNAME);
 
         final NetworkRequest networkRequest = new NetworkRequest.Builder()
                 .addTransportType(TRANSPORT_CELLULAR)
@@ -5939,15 +5940,13 @@
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
         cellLp.addLinkAddress(myIpv6);
-        cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
-        cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+        cellLp.addRoute(defaultRoute);
+        cellLp.addRoute(ipv6Subnet);
         mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
         reset(mNetworkManagementService);
         reset(mMockDnsResolver);
         reset(mMockNetd);
         reset(mBatteryStatsService);
-        when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
-                .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Connect with ipv6 link properties. Expect prefix discovery to be started.
         mCellNetworkAgent.connect(true);
@@ -5955,6 +5954,7 @@
         waitForIdle();
 
         verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
+        assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
         verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
         verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
                 TYPE_MOBILE);
@@ -5970,6 +5970,7 @@
         cellLp.addLinkAddress(myIpv4);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        assertRoutesAdded(cellNetId, ipv4Subnet);
         verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
         verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
 
@@ -5980,15 +5981,18 @@
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
+        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
+        when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+                .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Remove IPv4 address. Expect prefix discovery to be started again.
         cellLp.removeLinkAddress(myIpv4);
-        cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
+        assertRoutesRemoved(cellNetId, ipv4Subnet);
 
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent);
@@ -6007,6 +6011,7 @@
         List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
                 .getStackedLinks();
         assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
+        assertRoutesAdded(cellNetId, stackedDefault);
 
         // Change trivial linkproperties and see if stacked link is preserved.
         cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
@@ -6032,9 +6037,10 @@
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
         cellLp.addLinkAddress(myIpv4);
-        cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
+        cellLp.addRoute(ipv4Subnet);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        assertRoutesAdded(cellNetId, ipv4Subnet);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
         verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
 
@@ -6045,6 +6051,7 @@
         expected.setNat64Prefix(kNat64Prefix);
         assertEquals(expected, actualLpAfterIpv4);
         assertEquals(0, actualLpAfterIpv4.getStackedLinks().size());
+        assertRoutesRemoved(cellNetId, stackedDefault);
 
         // The interface removed callback happens but has no effect after stop is called.
         clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
@@ -6052,8 +6059,11 @@
 
         verifyNoMoreInteractions(mMockNetd);
         verifyNoMoreInteractions(mMockDnsResolver);
+        reset(mNetworkManagementService);
         reset(mMockNetd);
         reset(mMockDnsResolver);
+        when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+                .thenReturn(getClatInterfaceConfig(myIpv4));
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -6067,6 +6077,7 @@
         cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+        assertRoutesRemoved(cellNetId, ipv4Subnet);  // Directly-connected routes auto-added.
         verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
                 kNat64PrefixString, 96);
@@ -6078,15 +6089,20 @@
         clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
+        assertRoutesAdded(cellNetId, stackedDefault);
 
         // NAT64 prefix is removed. Expect that clat is stopped.
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
                 kNat64PrefixString, 96);
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
+        assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault);
+
+        // Stop has no effect because clat is already stopped.
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
         networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
                 (lp) -> lp.getStackedLinks().size() == 0);
+        verifyNoMoreInteractions(mMockNetd);
 
         // Clean up.
         mCellNetworkAgent.disconnect();
@@ -6654,6 +6670,20 @@
         }
     }
 
+    private void assertRoutesAdded(int netId, RouteInfo... routes) throws Exception {
+        InOrder inOrder = inOrder(mNetworkManagementService);
+        for (int i = 0; i < routes.length; i++) {
+            inOrder.verify(mNetworkManagementService).addRoute(eq(netId), eq(routes[i]));
+        }
+    }
+
+    private void assertRoutesRemoved(int netId, RouteInfo... routes) throws Exception {
+        InOrder inOrder = inOrder(mNetworkManagementService);
+        for (int i = 0; i < routes.length; i++) {
+            inOrder.verify(mNetworkManagementService).removeRoute(eq(netId), eq(routes[i]));
+        }
+    }
+
     @Test
     public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
         final NetworkRequest wifiRequest =
@@ -6715,7 +6745,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
                 new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), null,
+                        null, null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0);
 
         mServiceContext.setPermission(
@@ -6731,7 +6761,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
                 new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), null,
+                        null, null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0);
 
         mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -6747,7 +6777,7 @@
     public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception {
         final NetworkAgentInfo naiWithoutUid =
                 new NetworkAgentInfo(
-                        null, null, null, null, null, new NetworkCapabilities(), null,
+                        null, null, null, null, null, new NetworkCapabilities(), 0,
                         mServiceContext, null, null, mService, null, null, null, 0);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -6773,7 +6803,7 @@
         nc.setAdministratorUids(Arrays.asList(Process.myUid()));
         final NetworkAgentInfo naiWithUid =
                 new NetworkAgentInfo(
-                        null, null, null, null, null, nc, null, mServiceContext, null, null,
+                        null, null, null, null, null, nc, 0, mServiceContext, null, null,
                         mService, null, null, null, 0);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
@@ -6795,7 +6825,7 @@
         nc.setAdministratorUids(Arrays.asList(Process.myUid()));
         final NetworkAgentInfo naiWithUid =
                 new NetworkAgentInfo(
-                        null, null, null, null, null, nc, null, mServiceContext, null, null,
+                        null, null, null, null, null, nc, 0, mServiceContext, null, null,
                         mService, null, null, null, 0);
 
         setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index e863266..24a8717 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -38,7 +38,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
-import android.net.NetworkScore;
 import android.os.INetworkManagementService;
 import android.text.format.DateUtils;
 
@@ -353,10 +352,8 @@
         NetworkCapabilities caps = new NetworkCapabilities();
         caps.addCapability(0);
         caps.addTransportType(transport);
-        NetworkScore ns = new NetworkScore();
-        ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
+                caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
                 NetworkProvider.ID_NONE);
         nai.everValidated = true;
         return nai;
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index d57f225..47db5d4 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -238,20 +238,6 @@
     }
 
     @Test
-    public void testSameLevelNotifications() {
-        final int id = 101;
-        final String tag = NetworkNotificationManager.tagFor(id);
-
-        mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
-        verify(mNotificationManager, times(1))
-                .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
-
-        mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
-        verify(mNotificationManager, times(1))
-                .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
-    }
-
-    @Test
     public void testClearNotificationByType() {
         final int id = 101;
         final String tag = NetworkNotificationManager.tagFor(id);
@@ -259,31 +245,25 @@
         // clearNotification(int id, NotificationType notifyType) will check if given type is equal
         // to previous type or not. If they are equal then clear the notification; if they are not
         // equal then return.
-
-        mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
+        mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
         verify(mNotificationManager, times(1))
-                .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
+                .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
 
-        // Previous notification is LOGGED_IN and given type is LOGGED_IN too. The notification
+        // Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
         // should be cleared.
-        mManager.clearNotification(id, LOGGED_IN);
+        mManager.clearNotification(id, NO_INTERNET);
         verify(mNotificationManager, times(1))
-                .cancelAsUser(eq(tag), eq(LOGGED_IN.eventId), any());
+                .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
 
-        mManager.showNotification(id, LOGGED_IN, mWifiNai, mCellNai, null, false);
-        verify(mNotificationManager, times(2))
-                .notifyAsUser(eq(tag), eq(LOGGED_IN.eventId), any(), any());
-
-        // LOST_INTERNET notification popup after LOGGED_IN notification.
-        mManager.showNotification(id, LOST_INTERNET, mWifiNai, mCellNai, null, false);
+        // SIGN_IN is popped-up.
+        mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
         verify(mNotificationManager, times(1))
-                .notifyAsUser(eq(tag), eq(LOST_INTERNET.eventId), any(), any());
+                .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
 
-        // Previous notification is LOST_INTERNET and given type is LOGGED_IN. The notification
-        // shouldn't be cleared.
-        mManager.clearNotification(id, LOGGED_IN);
-        // LOST_INTERNET shouldn't be cleared.
+        // The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
+        // cleared.
+        mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
         verify(mNotificationManager, never())
-                .cancelAsUser(eq(tag), eq(LOST_INTERNET.eventId), any());
+                .cancelAsUser(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId), any());
     }
 }
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index a9e0b9a..36deca3 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -64,6 +64,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.NonNull;
 import android.app.AlarmManager;
 import android.app.usage.NetworkStatsManager;
 import android.content.Context;
@@ -163,7 +164,6 @@
     private @Mock IBinder mBinder;
     private @Mock AlarmManager mAlarmManager;
     private HandlerThread mHandlerThread;
-    private Handler mHandler;
 
     private NetworkStatsService mService;
     private INetworkStatsSession mSession;
@@ -192,15 +192,11 @@
         PowerManager.WakeLock wakeLock =
                 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
-        mService = new NetworkStatsService(
-                mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
-                mServiceContext.getSystemService(TelephonyManager.class), mSettings,
-                mStatsFactory, new NetworkStatsObservers(),  mStatsDir, getBaseDir(mStatsDir));
         mHandlerThread = new HandlerThread("HandlerThread");
-        mHandlerThread.start();
-        Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
-        mHandler = new Handler(mHandlerThread.getLooper(), callback);
-        mService.setHandler(mHandler, callback);
+        final NetworkStatsService.Dependencies deps = makeDependencies();
+        mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
+                mClock, mServiceContext.getSystemService(TelephonyManager.class), mSettings,
+                mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
 
         mElapsedRealtime = 0L;
 
@@ -217,11 +213,21 @@
 
         // catch INetworkManagementEventObserver during systemReady()
         ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
-              ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
+                ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
         verify(mNetManager).registerObserver(networkObserver.capture());
         mNetworkObserver = networkObserver.getValue();
     }
 
+    @NonNull
+    private NetworkStatsService.Dependencies makeDependencies() {
+        return new NetworkStatsService.Dependencies() {
+            @Override
+            public HandlerThread makeHandlerThread() {
+                return mHandlerThread;
+            }
+        };
+    }
+
     @After
     public void tearDown() throws Exception {
         IoUtils.deleteContents(mStatsDir);
@@ -234,6 +240,8 @@
 
         mSession.close();
         mService = null;
+
+        mHandlerThread.quitSafely();
     }
 
     @Test
@@ -939,9 +947,7 @@
         long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
         assertEquals(minThresholdInBytes, request.thresholdInBytes);
 
-        // Send dummy message to make sure that any previous message has been handled
-        mHandler.sendMessage(mHandler.obtainMessage(-1));
-        HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+        HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
 
         // Make sure that the caller binder gets connected
         verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
@@ -1077,7 +1083,7 @@
 
         // Simulates alert quota of the provider has been reached.
         cb.onAlertReached();
-        HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+        HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
 
         // Verifies that polling is triggered by alert reached.
         provider.expectStatsUpdate(0 /* unused */);
@@ -1294,9 +1300,7 @@
 
     private void forcePollAndWaitForIdle() {
         mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
-        // Send dummy message to make sure that any previous message has been handled
-        mHandler.sendMessage(mHandler.obtainMessage(-1));
-        HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+        HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
     }
 
     static class LatchedHandler extends Handler {
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index cbf6fe8..b1e2487 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -120,12 +120,6 @@
         "liblog",
         "libcutils",
     ],
-    apex_available: [
-        "//apex_available:platform",
-        //TODO(b/149781190): Remove this once statsd no longer depends on libstatslog
-        "com.android.os.statsd",
-        "test_com.android.os.statsd",
-    ],
     target: {
         android: {
             shared_libs: ["libstatssocket"],
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 91174d3..f4d2881 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -177,14 +177,14 @@
 java_library {
     name: "framework-wifi-stubs-publicapi",
     srcs: [":framework-wifi-stubs-srcs-publicapi"],
-    sdk_version: "module_current",
+    sdk_version: "current",
     installable: false,
 }
 
 java_library {
     name: "framework-wifi-stubs-systemapi",
     srcs: [":framework-wifi-stubs-srcs-systemapi"],
-    sdk_version: "module_current",
+    sdk_version: "system_current",
     libs: ["framework-annotations-lib"],
     installable: false,
 }
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
similarity index 82%
rename from wifi/java/android/net/wifi/IScoreChangeCallback.aidl
rename to wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
index d691f41..775fed7 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -21,9 +21,9 @@
  *
  * @hide
  */
-oneway interface IScoreChangeCallback
+oneway interface IScoreUpdateObserver
 {
-    void onScoreChange(int sessionId, int score);
+    void notifyScoreUpdate(int sessionId, int score);
 
-    void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+    void triggerUpdateOfWifiUsabilityStats(int sessionId);
 }
diff --git a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
index d9a3b01..f96d037 100644
--- a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
+++ b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
@@ -16,7 +16,7 @@
 
 package android.net.wifi;
 
-import android.net.wifi.IScoreChangeCallback;
+import android.net.wifi.IScoreUpdateObserver;
 
 /**
  * Interface for Wi-Fi connected network scorer.
@@ -25,9 +25,9 @@
  */
 oneway interface IWifiConnectedNetworkScorer
 {
-    void start(int sessionId);
+    void onStart(int sessionId);
 
-    void stop(int sessionId);
+    void onStop(int sessionId);
 
-    void setScoreChangeCallback(IScoreChangeCallback cbImpl);
+    void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl);
 }
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9256c57..70542b5 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,16 +16,15 @@
 
 package android.net.wifi;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -313,17 +312,6 @@
      */
     public static final int WIFI_STANDARD_11AX = 6;
 
-    /** @hide */
-    @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
-            WIFI_STANDARD_UNKNOWN,
-            WIFI_STANDARD_LEGACY,
-            WIFI_STANDARD_11N,
-            WIFI_STANDARD_11AC,
-            WIFI_STANDARD_11AX
-    })
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface WifiStandard{}
-
     /**
      * AP wifi standard.
      */
@@ -368,7 +356,7 @@
      * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
      * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
      */
-    public int channelWidth;
+    public @ChannelWidth int channelWidth;
 
     /**
      * Not used if the AP bandwidth is 20 MHz
diff --git a/wifi/java/android/net/wifi/WifiAnnotations.java b/wifi/java/android/net/wifi/WifiAnnotations.java
index 05e5b1d..acda7e0 100644
--- a/wifi/java/android/net/wifi/WifiAnnotations.java
+++ b/wifi/java/android/net/wifi/WifiAnnotations.java
@@ -61,6 +61,26 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Bandwidth {}
 
+    @IntDef(prefix = { "CHANNEL_WIDTH_" }, value = {
+            ScanResult.CHANNEL_WIDTH_20MHZ,
+            ScanResult.CHANNEL_WIDTH_40MHZ,
+            ScanResult.CHANNEL_WIDTH_80MHZ,
+            ScanResult.CHANNEL_WIDTH_160MHZ,
+            ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ChannelWidth{}
+
+    @IntDef(prefix = { "WIFI_STANDARD_" }, value = {
+            ScanResult.WIFI_STANDARD_UNKNOWN,
+            ScanResult.WIFI_STANDARD_LEGACY,
+            ScanResult.WIFI_STANDARD_11N,
+            ScanResult.WIFI_STANDARD_11AC,
+            ScanResult.WIFI_STANDARD_11AX,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WifiStandard{}
+
     @IntDef(prefix = { "PROTOCOL_" }, value = {
             ScanResult.PROTOCOL_NONE,
             ScanResult.PROTOCOL_WPA,
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5a7bf4b..e0b433d 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -498,11 +498,15 @@
                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                 requirePmf = true;
                 break;
             case SECURITY_TYPE_EAP_SUITE_B:
                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+                allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
@@ -515,7 +519,9 @@
                 allowedProtocols.set(WifiConfiguration.Protocol.RSN);
                 allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
                 allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+                allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
                 allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+                allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
                 requirePmf = true;
                 break;
             case SECURITY_TYPE_WAPI_PSK:
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 142854a..70c5e72 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -103,7 +103,7 @@
     /**
      * Wi-Fi standard for the connection
      */
-    private @ScanResult.WifiStandard int mWifiStandard;
+    private @WifiAnnotations.WifiStandard int mWifiStandard;
 
     /**
      * The unit in which links speeds are expressed.
@@ -518,7 +518,7 @@
      * Sets the Wi-Fi standard
      * @hide
      */
-    public void setWifiStandard(@ScanResult.WifiStandard int wifiStandard) {
+    public void setWifiStandard(@WifiAnnotations.WifiStandard int wifiStandard) {
         mWifiStandard = wifiStandard;
     }
 
@@ -526,7 +526,7 @@
      * Get connection Wi-Fi standard
      * @return the connection Wi-Fi standard
      */
-    public @ScanResult.WifiStandard int getWifiStandard() {
+    public @WifiAnnotations.WifiStandard int getWifiStandard() {
         return mWifiStandard;
     }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9703fa6..b5360a4 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2563,7 +2563,7 @@
      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
      * @return {@code true} if supported, {@code false} otherwise.
      */
-    public boolean isWifiStandardSupported(@ScanResult.WifiStandard int standard) {
+    public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) {
         try {
             return mService.isWifiStandardSupported(standard);
         } catch (RemoteException e) {
@@ -2826,7 +2826,7 @@
      */
     @Nullable
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public String getCountryCode() {
         try {
             return mService.getCountryCode();
@@ -3372,7 +3372,7 @@
      */
     @NonNull
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public SoftApConfiguration getSoftApConfiguration() {
         try {
             return mService.getSoftApConfiguration();
@@ -4989,7 +4989,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void factoryReset() {
         try {
             mService.factoryReset(mContext.getOpPackageName());
@@ -5986,22 +5986,22 @@
     }
 
     /**
-     * Callback interface for framework to receive network status changes and trigger of updating
+     * Callback interface for framework to receive network status updates and trigger of updating
      * {@link WifiUsabilityStatsEntry}.
      *
      * @hide
      */
     @SystemApi
-    public interface ScoreChangeCallback {
+    public interface ScoreUpdateObserver {
         /**
          * Called by applications to indicate network status.
          *
          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
-         *                  {@link WifiConnectedNetworkScorer#start(int)}.
+         *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
          * @param score The score representing link quality of current Wi-Fi network connection.
          *              Populated by connected network scorer in applications..
          */
-        void onScoreChange(int sessionId, int score);
+        void notifyScoreUpdate(int sessionId, int score);
 
         /**
          * Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -6009,36 +6009,36 @@
          * {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
          *
          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
-         *                  {@link WifiConnectedNetworkScorer#start(int)}.
+         *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
          */
-        void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+        void triggerUpdateOfWifiUsabilityStats(int sessionId);
     }
 
     /**
-     * Callback proxy for {@link ScoreChangeCallback} objects.
+     * Callback proxy for {@link ScoreUpdateObserver} objects.
      *
      * @hide
      */
-    private class ScoreChangeCallbackProxy implements ScoreChangeCallback {
-        private final IScoreChangeCallback mScoreChangeCallback;
+    private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
+        private final IScoreUpdateObserver mScoreUpdateObserver;
 
-        private ScoreChangeCallbackProxy(IScoreChangeCallback callback) {
-            mScoreChangeCallback = callback;
+        private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
+            mScoreUpdateObserver = observer;
         }
 
         @Override
-        public void onScoreChange(int sessionId, int score) {
+        public void notifyScoreUpdate(int sessionId, int score) {
             try {
-                mScoreChangeCallback.onScoreChange(sessionId, score);
+                mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
 
         @Override
-        public void onTriggerUpdateOfWifiUsabilityStats(int sessionId) {
+        public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
             try {
-                mScoreChangeCallback.onTriggerUpdateOfWifiUsabilityStats(sessionId);
+                mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -6058,21 +6058,21 @@
          * Called by framework to indicate the start of a network connection.
          * @param sessionId The ID to indicate current Wi-Fi network connection.
          */
-        void start(int sessionId);
+        void onStart(int sessionId);
 
         /**
          * Called by framework to indicate the end of a network connection.
          * @param sessionId The ID to indicate current Wi-Fi network connection obtained from
-         *                  {@link WifiConnectedNetworkScorer#start(int)}.
+         *                  {@link WifiConnectedNetworkScorer#onStart(int)}.
          */
-        void stop(int sessionId);
+        void onStop(int sessionId);
 
         /**
          * Framework sets callback for score change events after application sets its scorer.
-         * @param cbImpl The instance for {@link WifiManager#ScoreChangeCallback}. Should be
+         * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
          * implemented and instantiated by framework.
          */
-        void setScoreChangeCallback(@NonNull ScoreChangeCallback cbImpl);
+        void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
     }
 
     /**
@@ -6090,32 +6090,32 @@
         }
 
         @Override
-        public void start(int sessionId) {
+        public void onStart(int sessionId) {
             if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "WifiConnectedNetworkScorer: " + "start: sessionId=" + sessionId);
+                Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
             }
             Binder.clearCallingIdentity();
-            mExecutor.execute(() -> mScorer.start(sessionId));
+            mExecutor.execute(() -> mScorer.onStart(sessionId));
         }
 
         @Override
-        public void stop(int sessionId) {
+        public void onStop(int sessionId) {
             if (mVerboseLoggingEnabled) {
-                Log.v(TAG, "WifiConnectedNetworkScorer: " + "stop: sessionId=" + sessionId);
+                Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
             }
             Binder.clearCallingIdentity();
-            mExecutor.execute(() -> mScorer.stop(sessionId));
+            mExecutor.execute(() -> mScorer.onStop(sessionId));
         }
 
         @Override
-        public void setScoreChangeCallback(IScoreChangeCallback cbImpl) {
+        public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
             if (mVerboseLoggingEnabled) {
                 Log.v(TAG, "WifiConnectedNetworkScorer: "
-                        + "setScoreChangeCallback: cbImpl=" + cbImpl);
+                        + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
             }
             Binder.clearCallingIdentity();
-            mExecutor.execute(() -> mScorer.setScoreChangeCallback(
-                    new ScoreChangeCallbackProxy(cbImpl)));
+            mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
+                    new ScoreUpdateObserverProxy(observerImpl)));
         }
     }
 
diff --git a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
index a045aad..bb0cc97 100644
--- a/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
+++ b/wifi/java/android/net/wifi/nl80211/DeviceWiphyCapabilities.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.net.wifi.ScanResult;
+import android.net.wifi.WifiAnnotations.ChannelWidth;
+import android.net.wifi.WifiAnnotations.WifiStandard;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
@@ -28,6 +30,9 @@
 /**
  * DeviceWiphyCapabilities for wificond
  *
+ * Contains the WiFi physical layer attributes and capabilities of the device.
+ * It is used to collect these attributes from the device driver via wificond.
+ *
  * @hide
  */
 @SystemApi
@@ -61,7 +66,7 @@
      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
      * @return {@code true} if supported, {@code false} otherwise.
      */
-    public boolean isWifiStandardSupported(int standard) {
+    public boolean isWifiStandardSupported(@WifiStandard int standard) {
         switch (standard) {
             case ScanResult.WIFI_STANDARD_LEGACY:
                 return true;
@@ -84,7 +89,7 @@
      *        valid values from {@link ScanResult}'s {@code WIFI_STANDARD_}
      * @param support {@code true} if supported, {@code false} otherwise.
      */
-    public void setWifiStandardSupport(int standard, boolean support) {
+    public void setWifiStandardSupport(@WifiStandard int standard, boolean support) {
         switch (standard) {
             case ScanResult.WIFI_STANDARD_11N:
                 m80211nSupported = support;
@@ -107,7 +112,7 @@
      *
      * @return {@code true} if supported, {@code false} otherwise.
      */
-    public boolean isChannelWidthSupported(int chWidth) {
+    public boolean isChannelWidthSupported(@ChannelWidth int chWidth) {
         switch (chWidth) {
             case ScanResult.CHANNEL_WIDTH_20MHZ:
                 return true;
@@ -131,8 +136,10 @@
      * @param chWidth valid values are {@link ScanResult#CHANNEL_WIDTH_160MHZ} and
      *        {@link ScanResult#CHANNEL_WIDTH_80MHZ_PLUS_MHZ}
      * @param support {@code true} if supported, {@code false} otherwise.
+     *
+     * @hide
      */
-    public void setChannelWidthSupported(int chWidth, boolean support) {
+    public void setChannelWidthSupported(@ChannelWidth int chWidth, boolean support) {
         switch (chWidth) {
             case ScanResult.CHANNEL_WIDTH_160MHZ:
                 mChannelWidth160MhzSupported = support;
@@ -159,6 +166,8 @@
      * Set maximum number of transmit spatial streams
      *
      * @param streams number of spatial streams
+     *
+     * @hide
      */
     public void setMaxNumberTxSpatialStreams(int streams) {
         mMaxNumberTxSpatialStreams = streams;
@@ -177,6 +186,8 @@
      * Set maximum number of receive spatial streams
      *
      * @param streams number of streams
+     *
+     * @hide
      */
     public void setMaxNumberRxSpatialStreams(int streams) {
         mMaxNumberRxSpatialStreams = streams;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 9c2cad9..a310ff6 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1805,9 +1805,7 @@
      * @hide
      */
     @SystemApi
-    @RequiresPermission(allOf = {
-            android.Manifest.permission.CONNECTIVITY_INTERNAL,
-            android.Manifest.permission.CONFIGURE_WIFI_DISPLAY})
+    @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
     public void setMiracastMode(@MiracastMode int mode) {
         try {
             mService.setMiracastMode(mode);
diff --git a/wifi/tests/src/android/net/wifi/ScanResultTest.java b/wifi/tests/src/android/net/wifi/ScanResultTest.java
index b5c74d1..4c22d5d 100644
--- a/wifi/tests/src/android/net/wifi/ScanResultTest.java
+++ b/wifi/tests/src/android/net/wifi/ScanResultTest.java
@@ -42,7 +42,7 @@
     public static final int TEST_LEVEL = -56;
     public static final int TEST_FREQUENCY = 2412;
     public static final long TEST_TSF = 04660l;
-    public static final @ScanResult.WifiStandard int TEST_WIFI_STANDARD =
+    public static final @WifiAnnotations.WifiStandard int TEST_WIFI_STANDARD =
             ScanResult.WIFI_STANDARD_11AC;
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 047a64b..e210e4f 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -423,7 +423,9 @@
 
         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
         assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
         assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
         assertTrue(config.requirePmf);
     }
 
@@ -440,7 +442,9 @@
 
         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
         assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+        assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
         assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+        assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
         assertTrue(config.requirePmf);
     }
 
@@ -456,6 +460,8 @@
         config.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B);
 
         assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+        assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP));
+        assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X));
         assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
         assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
         assertTrue(config.allowedGroupManagementCiphers
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 76ac837..90d6241 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2349,23 +2349,24 @@
     }
 
     /**
-     * Verify that Wi-Fi connected scorer receives score change callback after registeration.
+     * Verify that Wi-Fi connected scorer receives score update observer after registeration.
      */
     @Test
-    public void verifyScorerReceiveScoreChangeCallbackAfterRegistration() throws Exception {
+    public void verifyScorerReceiveScoreUpdateObserverAfterRegistration() throws Exception {
         mExecutor = new SynchronousExecutor();
         mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
         ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> scorerCaptor =
                 ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
         verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
                 scorerCaptor.capture());
-        scorerCaptor.getValue().setScoreChangeCallback(any());
+        scorerCaptor.getValue().onSetScoreUpdateObserver(any());
         mLooper.dispatchAll();
-        verify(mWifiConnectedNetworkScorer).setScoreChangeCallback(any());
+        verify(mWifiConnectedNetworkScorer).onSetScoreUpdateObserver(any());
     }
 
     /**
-     * Verify that Wi-Fi connected scorer receives session ID when start/stop methods are called.
+     * Verify that Wi-Fi connected scorer receives session ID when onStart/onStop methods
+     * are called.
      */
     @Test
     public void verifyScorerReceiveSessionIdWhenStartStopIsCalled() throws Exception {
@@ -2375,11 +2376,11 @@
                 ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
         verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
                 callbackCaptor.capture());
-        callbackCaptor.getValue().start(0);
-        callbackCaptor.getValue().stop(10);
+        callbackCaptor.getValue().onStart(0);
+        callbackCaptor.getValue().onStop(10);
         mLooper.dispatchAll();
-        verify(mWifiConnectedNetworkScorer).start(0);
-        verify(mWifiConnectedNetworkScorer).stop(10);
+        verify(mWifiConnectedNetworkScorer).onStart(0);
+        verify(mWifiConnectedNetworkScorer).onStop(10);
     }
 
     @Test